Remove `install into build-env` from `build_python.sh` (#27437)

* Start removing the option for install_wheel in the build environment

* Move java tests to use a separate build environment

* Update openiotsdk ... i am unclear why the python controller was built at all, but testing out and expecting compile errors.

* Remove force reinstall option as it should not be needed on clean environments

* Restyle

* Fix typo

* Update tests.yaml for the new args as well

* Update openiotsdk to run tests in the configured venv

* Ensure more pip packages available in venv, at least click and probably more

* Update one guide and tests

* update java tests to install basic prerequisites

* Install yaml tests requirement in venv

* Restyle

* Update openiot to not automatically activate every time

* Restyle

* Install colorama in unit test venv

* add colorama to java tests venv as well

* Add pyasn1 to items install by the repl tests

* Install more required items
diff --git a/.github/workflows/examples-openiotsdk.yaml b/.github/workflows/examples-openiotsdk.yaml
index 3ef77aa..03c2670 100644
--- a/.github/workflows/examples-openiotsdk.yaml
+++ b/.github/workflows/examples-openiotsdk.yaml
@@ -84,7 +84,8 @@
             - name: Build and install Python controller
               timeout-minutes: 10
               run: |
-                  scripts/run_in_build_env.sh './scripts/build_python.sh --install_wheel build-env'
+                  scripts/run_in_build_env.sh './scripts/build_python.sh --install_virtual_env out/venv'
+                  scripts/run_in_python_env.sh out/venv 'pip install -r scripts/setup/requirements.openiotsdk.txt'
 
             - name: Build shell example
               id: build_shell
@@ -116,18 +117,21 @@
               if: steps.build_shell.outcome == 'success'
               timeout-minutes: 5
               run: |
-                  scripts/examples/openiotsdk_example.sh -C test shell
+                  scripts/run_in_python_env.sh out/venv \
+                    'scripts/examples/openiotsdk_example.sh --no-activate -C test shell'
 
             - name: "Test: lock-app example"
               if: steps.build_lock_app.outcome == 'success'
               timeout-minutes: 5
               run: |
                   scripts/setup/openiotsdk/network_setup.sh -n $TEST_NETWORK_NAME up
-                  scripts/run_in_ns.sh ${TEST_NETWORK_NAME}ns scripts/examples/openiotsdk_example.sh -C test -n ${TEST_NETWORK_NAME}tap lock-app
+                  scripts/run_in_python_env.sh out/venv \
+                    'scripts/run_in_ns.sh ${TEST_NETWORK_NAME}ns scripts/examples/openiotsdk_example.sh --no-activate -C test -n ${TEST_NETWORK_NAME}tap lock-app'
                   scripts/setup/openiotsdk/network_setup.sh -n $TEST_NETWORK_NAME down
 
             - name: "Test: unit-tests"
               if: steps.build_unit_tests.outcome == 'success'
               timeout-minutes: 40
               run: |
-                  scripts/examples/openiotsdk_example.sh -C test unit-tests
+                  scripts/run_in_python_env.sh out/venv \
+                    'scripts/examples/openiotsdk_example.sh --no-activate -C test unit-tests'
diff --git a/.github/workflows/java-tests.yaml b/.github/workflows/java-tests.yaml
index b76c379..a0fb06a 100644
--- a/.github/workflows/java-tests.yaml
+++ b/.github/workflows/java-tests.yaml
@@ -110,7 +110,9 @@
             - name: Build Java Matter Controller and all clusters app
               timeout-minutes: 60
               run: |
-                  scripts/run_in_build_env.sh './scripts/build_python.sh --install_wheel build-env'
+                  scripts/run_in_build_env.sh './scripts/build_python.sh --install_virtual_env out/venv'
+                  scripts/run_in_python_env.sh out/venv 'pip install -r scripts/setup/requirements.build.txt'
+                  scripts/run_in_python_env.sh out/venv 'pip install colorama'
                   ./scripts/run_in_build_env.sh \
                    "./scripts/build/build_examples.py \
                       --target linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test \
@@ -120,7 +122,7 @@
             - name: Run Discover Commissionables Test
               timeout-minutes: 15
               run: |
-                  scripts/run_in_build_env.sh \
+                  scripts/run_in_python_env.sh out/venv \
                   './scripts/tests/run_java_test.py \
                      --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app \
                      --app-args "--discriminator 3840 --interface-id -1" \
@@ -132,7 +134,7 @@
             - name: Run Pairing Onnetwork Test
               timeout-minutes: 15
               run: |
-                  scripts/run_in_build_env.sh \
+                  scripts/run_in_python_env.sh out/venv \
                   './scripts/tests/run_java_test.py \
                      --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app \
                      --app-args "--discriminator 3840 --interface-id -1" \
@@ -144,7 +146,7 @@
             - name: Run IM Invoke Test
               timeout-minutes: 15
               run: |
-                  scripts/run_in_build_env.sh \
+                  scripts/run_in_python_env.sh out/venv \
                   './scripts/tests/run_java_test.py \
                      --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app \
                      --app-args "--discriminator 3840 --interface-id -1" \
@@ -156,7 +158,7 @@
             - name: Run IM Read Test
               timeout-minutes: 15
               run: |
-                  scripts/run_in_build_env.sh \
+                  scripts/run_in_python_env.sh out/venv \
                   './scripts/tests/run_java_test.py \
                      --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app \
                      --app-args "--discriminator 3840 --interface-id -1" \
@@ -168,7 +170,7 @@
             - name: Run IM Write Test
               timeout-minutes: 15
               run: |
-                  scripts/run_in_build_env.sh \
+                  scripts/run_in_python_env.sh out/venv \
                   './scripts/tests/run_java_test.py \
                      --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app \
                      --app-args "--discriminator 3840 --interface-id -1" \
@@ -180,7 +182,7 @@
             - name: Run IM Subscribe Test
               timeout-minutes: 15
               run: |
-                  scripts/run_in_build_env.sh \
+                  scripts/run_in_python_env.sh out/venv \
                   './scripts/tests/run_java_test.py \
                      --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app \
                      --app-args "--discriminator 3840 --interface-id -1" \
@@ -192,7 +194,7 @@
             - name: Run Pairing AlreadyDiscovered Test
               timeout-minutes: 25
               run: |
-                  scripts/run_in_build_env.sh \
+                  scripts/run_in_python_env.sh out/venv \
                   './scripts/tests/run_java_test.py \
                      --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app \
                      --app-args "--discriminator 3840 --interface-id -1" \
@@ -205,7 +207,7 @@
             # - name: Run Pairing Address-PaseOnly Test
             #   timeout-minutes: 25
             #   run: |
-            #       scripts/run_in_build_env.sh \
+            #      scripts/run_in_python_env.sh out/venv \
             #       './scripts/tests/run_java_test.py \
             #          --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app \
             #          --app-args "--discriminator 3840 --interface-id -1" \
@@ -217,7 +219,7 @@
             - name: Run Pairing SetupQRCode Test
               timeout-minutes: 25
               run: |
-                  scripts/run_in_build_env.sh \
+                  scripts/run_in_python_env.sh out/venv \
                   './scripts/tests/run_java_test.py \
                      --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app \
                      --app-args "--discriminator 3840 --interface-id -1" \
@@ -229,7 +231,7 @@
             - name: Run Pairing ManualCode Test
               timeout-minutes: 25
               run: |
-                  scripts/run_in_build_env.sh \
+                  scripts/run_in_python_env.sh out/venv \
                   './scripts/tests/run_java_test.py \
                      --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app \
                      --app-args "--discriminator 3840 --interface-id -1" \
diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml
index 0e4252a..a45ab21 100644
--- a/.github/workflows/tests.yaml
+++ b/.github/workflows/tests.yaml
@@ -215,7 +215,9 @@
             - name: Build Apps
               timeout-minutes: 60
               run: |
-                  scripts/run_in_build_env.sh './scripts/build_python.sh --install_wheel build-env --include_yamltests'
+                  scripts/run_in_build_env.sh './scripts/build_python.sh --install_virtual_env out/venv --include_yamltests'
+                  scripts/run_in_python_env.sh out/venv 'pip install -r scripts/setup/requirements.build.txt'
+                  scripts/run_in_python_env.sh out/venv 'pip install -r scripts/setup/requirements.yaml_tests.txt'
                   ./scripts/run_in_build_env.sh \
                      "./scripts/build/build_examples.py \
                         --target linux-x64-chip-tool${CHIP_TOOL_VARIANT}-${BUILD_VARIANT} \
@@ -267,7 +269,7 @@
               timeout-minutes: 45
               if: github.event_name == 'pull_request'
               run: |
-                  ./scripts/run_in_build_env.sh \
+                  ./scripts/run_in_python_env.sh out/venv \
                   "./scripts/tests/run_test_suite.py \
                      --runner chip_repl_python \
                      --exclude-tags MANUAL \
@@ -288,7 +290,7 @@
               timeout-minutes: 45
               if: github.event_name == 'push'
               run: |
-                  ./scripts/run_in_build_env.sh \
+                  ./scripts/run_in_python_env.sh out/venv \
                   "./scripts/tests/run_test_suite.py \
                      --runner chip_repl_python \
                      run \
@@ -513,7 +515,9 @@
             - name: Build Python REPL and example apps
               timeout-minutes: 50
               run: |
-                  scripts/run_in_build_env.sh './scripts/build_python.sh --install_wheel build-env --extra_packages "mobly"'
+                  scripts/run_in_build_env.sh './scripts/build_python.sh --install_virtual_env out/venv --extra_packages "mobly"'
+                  scripts/run_in_python_env.sh out/venv 'pip install -r scripts/setup/requirements.build.txt'
+                  scripts/run_in_python_env.sh out/venv 'pip install colorama pyasn1 pyasn1_modules'
                   ./scripts/run_in_build_env.sh \
                    "./scripts/build/build_examples.py \
                       --target linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test \
@@ -524,18 +528,18 @@
             - name: Run Tests
               timeout-minutes: 10
               run: |
-                  scripts/run_in_build_env.sh './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --script-args "--log-level INFO -t 3600 --disable-test ClusterObjectTests.TestTimedRequestTimeout"'
-                  scripts/run_in_build_env.sh './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app  --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_decode 1" --script "src/python_testing/TC_RR_1_1.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021"'
-                  scripts/run_in_build_env.sh './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app  --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_decode 1" --script "src/python_testing/TC_DeviceBasicComposition.py" --script-args "--storage-path admin_storage.json --manual-code 10054912339"'
-                  scripts/run_in_build_env.sh './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app  --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_decode 1" --script "src/python_testing/TC_SC_3_6.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021"'
-                  scripts/run_in_build_env.sh './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app  --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_decode 1" --script "src/python_testing/TC_DA_1_7.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --bool-arg allow_sdk_dac:true"'
-                  scripts/run_in_build_env.sh './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app  --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_decode 1 --enable-key 000102030405060708090a0b0c0d0e0f" --script "src/python_testing/TC_TestEventTrigger.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --bool-arg allow_sdk_dac:true"'
-                  scripts/run_in_build_env.sh './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app  --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_decode 1" --script "src/python_testing/TC_ACE_1_4.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --int-arg PIXIT.ACE.APPENDPOINT:1 PIXIT.ACE.APPDEVTYPEID:0x0100 --string-arg PIXIT.ACE.APPCLUSTER:OnOff PIXIT.ACE.APPATTRIBUTE:OnOff"'
-                  scripts/run_in_build_env.sh './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app  --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_decode 1" --script "src/python_testing/TC_ACE_1_3.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021"'
-                  scripts/run_in_build_env.sh './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app  --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_decode 1" --script "src/python_testing/TC_CGEN_2_4.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021"'
-                  scripts/run_in_build_env.sh './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app  --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_decode 1" --script "src/python_testing/TC_DA_1_2.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --PICS src/app/tests/suites/certification/ci-pics-values"'
-                  scripts/run_in_build_env.sh './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app  --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_decode 1" --script "src/python_testing/TC_DA_1_5.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --PICS src/app/tests/suites/certification/ci-pics-values"'
-                  scripts/run_in_build_env.sh './scripts/tests/run_python_test.py --script "src/python_testing/TestMatterTestingSupport.py"'
+                  scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --script-args "--log-level INFO -t 3600 --disable-test ClusterObjectTests.TestTimedRequestTimeout"'
+                  scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app  --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_decode 1" --script "src/python_testing/TC_RR_1_1.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021"'
+                  scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app  --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_decode 1" --script "src/python_testing/TC_DeviceBasicComposition.py" --script-args "--storage-path admin_storage.json --manual-code 10054912339"'
+                  scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app  --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_decode 1" --script "src/python_testing/TC_SC_3_6.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021"'
+                  scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app  --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_decode 1" --script "src/python_testing/TC_DA_1_7.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --bool-arg allow_sdk_dac:true"'
+                  scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app  --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_decode 1 --enable-key 000102030405060708090a0b0c0d0e0f" --script "src/python_testing/TC_TestEventTrigger.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --bool-arg allow_sdk_dac:true"'
+                  scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app  --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_decode 1" --script "src/python_testing/TC_ACE_1_4.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --int-arg PIXIT.ACE.APPENDPOINT:1 PIXIT.ACE.APPDEVTYPEID:0x0100 --string-arg PIXIT.ACE.APPCLUSTER:OnOff PIXIT.ACE.APPATTRIBUTE:OnOff"'
+                  scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app  --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_decode 1" --script "src/python_testing/TC_ACE_1_3.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021"'
+                  scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app  --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_decode 1" --script "src/python_testing/TC_CGEN_2_4.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021"'
+                  scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app  --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_decode 1" --script "src/python_testing/TC_DA_1_2.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --PICS src/app/tests/suites/certification/ci-pics-values"'
+                  scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app  --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_decode 1" --script "src/python_testing/TC_DA_1_5.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --PICS src/app/tests/suites/certification/ci-pics-values"'
+                  scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --script "src/python_testing/TestMatterTestingSupport.py"'
             - name: Uploading core files
               uses: actions/upload-artifact@v3
               if: ${{ failure() && !env.ACT }}
@@ -611,7 +615,9 @@
             - name: Build Python REPL and example apps
               timeout-minutes: 50
               run: |
-                  scripts/run_in_build_env.sh './scripts/build_python.sh --install_wheel build-env'
+                  scripts/run_in_build_env.sh './scripts/build_python.sh --install_virtual_env out/venv'
+                  scripts/run_in_python_env.sh out/venv 'pip install -r scripts/setup/requirements.build.txt'
+                  scripts/run_in_python_env.sh out/venv 'pip install colorama'
                   ./scripts/run_in_build_env.sh \
                    "./scripts/build/build_examples.py \
                       --target darwin-x64-all-clusters-${BUILD_VARIANT}-test \
@@ -621,7 +627,7 @@
             - name: Run Tests
               timeout-minutes: 30
               run: |
-                  scripts/run_in_build_env.sh './scripts/tests/run_python_test.py --app out/darwin-x64-all-clusters-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 3840 --interface-id -1" --script-args "-t 3600 --disable-test ClusterObjectTests.TestTimedRequestTimeout"'
+                  scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/darwin-x64-all-clusters-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 3840 --interface-id -1" --script-args "-t 3600 --disable-test ClusterObjectTests.TestTimedRequestTimeout"'
             - name: Uploading core files
               uses: actions/upload-artifact@v3
               if: ${{ failure() && !env.ACT }}
diff --git a/docs/guides/matter-repl.md b/docs/guides/matter-repl.md
index 5577881..2654884 100644
--- a/docs/guides/matter-repl.md
+++ b/docs/guides/matter-repl.md
@@ -54,7 +54,7 @@
    the -z argument that points to the directory of pre-generated code:
 
     ```
-    scripts/build_python.sh -m platform -i separate -z "/some/pregen/dir"
+    scripts/build_python.sh -m platform -i out/python_env -z "/some/pregen/dir"
     ```
 
     > Note: To get more details about available build configurations, run the
diff --git a/docs/guides/openiotsdk_examples.md b/docs/guides/openiotsdk_examples.md
index 2de1915..158691d 100644
--- a/docs/guides/openiotsdk_examples.md
+++ b/docs/guides/openiotsdk_examples.md
@@ -268,8 +268,10 @@
 following command from the CLI:
 
 ```
-${MATTER_ROOT}/scripts/run_in_build_env.sh './scripts/build_python.sh --install_wheel
-build-env'
+${MATTER_ROOT}/scripts/run_in_build_env.sh \
+    './scripts/build_python.sh --install_virtual_env out/venv'
+
+source out/venv/bin/activate
 ```
 
 More information about the Python tools you can find
diff --git a/scripts/build_python.sh b/scripts/build_python.sh
index 3e360dd..6cc3d09 100755
--- a/scripts/build_python.sh
+++ b/scripts/build_python.sh
@@ -36,13 +36,13 @@
 
 CHIP_ROOT=$(_normpath "$(dirname "$0")/..")
 OUTPUT_ROOT="$CHIP_ROOT/out/python_lib"
-ENVIRONMENT_ROOT="$CHIP_ROOT/out/python_env"
 
 declare chip_detail_logging=false
 declare enable_pybindings=false
 declare chip_mdns
 declare case_retry_delta
-declare install_wheel=no
+declare install_virtual_env
+declare clean_virtual_env=yes
 
 help() {
 
@@ -59,10 +59,10 @@
 
   -t --time_between_case_retries MRPActiveRetryInterval     Specify MRPActiveRetryInterval value
                                                             Default is 300 ms
-  -i, --install_wheel no|build-env|separate                 Where to install the Python wheel
-                                                            no: Do not install
-                                                            build-env: install to virtual env for build matter
-                                                            separate: install to another virtual env (out/python_env)
+  -i, --install_virtual_env <path>                          Create a virtual environment with the wheels installed
+                                                            <path> represents where the virtual environment is to be created.
+  -c, --clean_virtual_env  <yes|no>                         When installing a virtual environment, create/clean it first.
+                                                            Defaults to yes.
   --extra_packages PACKAGES                                 Install extra Python packages from PyPI
   --include_yamltests                                       Whether to install the matter_yamltests wheel.
   -z --pregen_dir DIRECTORY                                 Directory where generated zap files have been pre-generated.
@@ -93,8 +93,12 @@
             chip_case_retry_delta=$2
             shift
             ;;
-        --install_wheel | -i)
-            install_wheel=$2
+        --install_virtual_env | -i)
+            install_virtual_env=$2
+            shift
+            ;;
+        --clean_virtual_env | -c)
+            clean_virtual_env=$2
             shift
             ;;
         --extra_packages)
@@ -169,15 +173,17 @@
     WHEEL+=("$extra_packages")
 fi
 
-if [ "$install_wheel" = "no" ]; then
-    exit 0
-elif [ "$install_wheel" = "separate" ]; then
-    # Create a virtual environment that has access to the built python tools
-    virtualenv --clear "$ENVIRONMENT_ROOT"
+if [ -n "$install_virtual_env" ]; then
+    ENVIRONMENT_ROOT="$install_virtual_env"
+
+    if [ "$clean_virtual_env" = "yes" ]; then
+        # Create a virtual environment that has access to the built python tools
+        virtualenv --clear "$ENVIRONMENT_ROOT"
+    fi
 
     source "$ENVIRONMENT_ROOT"/bin/activate
     "$ENVIRONMENT_ROOT"/bin/python -m pip install --upgrade pip
-    "$ENVIRONMENT_ROOT"/bin/pip install --upgrade --force-reinstall "${WHEEL[@]}"
+    "$ENVIRONMENT_ROOT"/bin/pip install --upgrade "${WHEEL[@]}"
 
     echo ""
     echo_green "Compilation completed and WHL package installed in: "
@@ -185,12 +191,4 @@
     echo ""
     echo_green "To use please run:"
     echo_bold_white "  source $ENVIRONMENT_ROOT/bin/activate"
-elif [ "$install_wheel" = "build-env" ]; then
-    pip install --force-reinstall "${WHEEL[@]}"
-
-    echo ""
-    echo_green "Compilation completed and WHL package installed in virtualenv for building sdk"
-    echo ""
-    echo_green "To use please run:"
-    echo_bold_white "  source $CHIP_ROOT/scripts/activate.sh"
 fi
diff --git a/scripts/examples/openiotsdk_example.sh b/scripts/examples/openiotsdk_example.sh
index 6b19a8b..496fc04 100755
--- a/scripts/examples/openiotsdk_example.sh
+++ b/scripts/examples/openiotsdk_example.sh
@@ -43,6 +43,7 @@
 FVP_NETWORK="user"
 KVS_STORAGE_TYPE="tdb"
 KVS_STORAGE_FILE=""
+NO_ACTIVATE=""
 
 declare -A tdb_storage_param=([instance]=sram [memspace]=0 [address]=0x0 [size]=0x100000)
 declare -A ps_storage_param=([instance]=qspi_sram [memspace]=0 [address]=0x660000 [size]=0x12000)
@@ -69,7 +70,7 @@
     -p,--path       <build_path>        Build path <build_path - default is example_dir/build>
     -K,--kvsfile    <kvs_storage_file>  Path to KVS storage file which will be used to ensure persistence <kvs_storage_file - default is empty which means disable persistence>
     -n,--network    <network_name>      FVP network interface name <network_name - default is "user" which means user network mode>
-
+    --no-activate                       Do not activate the chip build environment
 Examples:
 EOF
 
@@ -269,7 +270,7 @@
 }
 
 SHORT=C:,p:,d:,l:,n:,k:,K:,c,s,h
-LONG=command:,path:,debug:,lwipdebug:,network:,kvsstore:,kvsfile:,clean,scratch,help
+LONG=command:,path:,debug:,lwipdebug:,network:,kvsstore:,kvsfile:,clean,scratch,help,no-activate
 OPTS=$(getopt -n build --options "$SHORT" --longoptions "$LONG" -- "$@")
 
 eval set -- "$OPTS"
@@ -316,6 +317,10 @@
             FVP_NETWORK=$2
             shift 2
             ;;
+        --no-activate)
+            NO_ACTIVATE='YES'
+            shift
+            ;;
         -* | --*)
             shift
             break
@@ -386,8 +391,10 @@
     BUILD_PATH="$EXAMPLE_PATH/build"
 fi
 
-# Activate Matter environment
-source "$CHIP_ROOT"/scripts/activate.sh
+if [ -z "$NO_ACTIVATE" ]; then
+    # Activate Matter environment
+    source "$CHIP_ROOT"/scripts/activate.sh
+fi
 
 if [[ $IS_UNIT_TEST -eq 0 ]]; then
     EXAMPLE_EXE_PATH="$BUILD_PATH/chip-openiotsdk-$EXAMPLE-example.elf"
diff --git a/scripts/run_in_python_env.sh b/scripts/run_in_python_env.sh
new file mode 100755
index 0000000..eca4168
--- /dev/null
+++ b/scripts/run_in_python_env.sh
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+#
+# Copyright (c) 2020 Project CHIP Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# This script executes the command given as an argument after
+# activating the given python virtual environment
+set -e
+
+_VENV_PATH="$1"
+shift
+
+source "$_VENV_PATH/bin/activate"
+
+echo "Executing in python environment $_VENV_PATH: $*"
+bash -c -- "$@"