forked from fohrloop/pathtub
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Added ensure() and clean() functions - More detailed examples and updated README.md
- Loading branch information
Niko Pasanen
committed
Apr 11, 2020
1 parent
b1484f6
commit da06d50
Showing
11 changed files
with
734 additions
and
178 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,149 +1,70 @@ | ||
## pathtub | ||
## 🛁 pathtub 🐍 | ||
|
||
Simple python functions for reading and editing Windows PATH. | ||
Simple python functions for reading and editing [Windows PATH variables](docs/path_variables.md). | ||
|
||
|
||
|
||
|
||
### Features | ||
- Uses Powershell commands under the hood | ||
- `$Env:Path` | ||
- `[Environment]::GetEnvironmentVariable(...)` | ||
- `[Environment]::SetEnvironmentVariable(...)` | ||
- Is not limited by the [1024 character limit](https://superuser.com/questions/387619/overcoming-the-1024-character-limit-with-setx). | ||
✅ **Ensuring** that an folder exists in Path. <br> | ||
🧽 **Cleaning** the PATH (duplicates, removed folders, sorting) <br> | ||
✏️ **Adding** or **removing** folders to/from Path (temporary or permanently) <br> | ||
|
||
|
||
|
||
## Installing | ||
### Option A: Install from PyPi | ||
``` | ||
pip install pathtub | ||
``` | ||
|
||
### Option B: Install from GitHub | ||
- Download this package and run | ||
``` | ||
pip install <this_folder_path> | ||
``` | ||
where `<this_folder_path>` refers to the folder with the `setup.py`. | ||
|
||
## Usage | ||
|
||
# Usage | ||
- [Getting path variables](#getting-path-variables) | ||
- [Setting PATH (User) variables](#setting-path-user-variables) | ||
- [Setting PATH (System/Machine) variables](#setting-path-systemmachine-variables) | ||
- [Removing PATH (User) variables](#removing-path-user-variables) | ||
- [Removing PATH (System/Machine) variables](#removing-path-systemmachine-variables) | ||
- [Checking if folder is in PATH](#checking-if-folder-is-in-path) | ||
- [Ensuring folder is in PATH](#%e2%9c%85-ensuring-folder-is-in-path) | ||
- [Cleaning PATH](#%f0%9f%a7%bd-cleaning-path) | ||
- [Rest of the docs](#rest-of-the-docs) | ||
|
||
### ✅ Ensuring folder is in PATH | ||
- It is safe to call `ensure()` every time you load your script, for example. It only does something if the dll_folder is not found in your process `PATH`. | ||
- The last "trailing" backslash (if any) is ignored when comparing any two folders. | ||
|
||
### Getting path variables | ||
```python | ||
from pathtub import get_path | ||
|
||
# Reads $Env:Path | ||
path = get_path() | ||
# Reads [Environment]::GetEnvironmentVariable('Path', 'User') | ||
path_user = get_path("user") | ||
# Reads [Environment]::GetEnvironmentVariable('Path', 'Machine') | ||
path_machine = get_path("machine") | ||
from pathtub import ensure | ||
dll_folder = r'C:\my favourite\dlls' | ||
# 1) Check Process PATH, i.e. os.environ['PATH'] | ||
# 2) Add to Process PATH (temporary) if not found | ||
ensure(dll_folder) | ||
``` | ||
#### Example output | ||
- You may also make the addition permanent (& visible to other processes). | ||
- Also this is safe to call every time script is starting. | ||
```python | ||
In [1]: print(get_path('user')) # returns a str | ||
C:\Python\Python37\Scripts\;C:\Python\Python37\;C:\Python\Python37-32\Scripts\;C:\Python\Python37-32\;C:\Users\USER\AppData\Roaming\npm;C:\Users\USER\AppData\Local\Microsoft\WindowsApps;C:\Program Files\Microsoft VS Code\bin;C:\Programs;C:\Programs\fciv;C:\texlive\2018\bin\win32;C:\Programs\apache-maven-3.6.2\bin;C:\Program Files\Java\jdk-13.0.1\bin;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Programs\cloc;C:\Users\USER\AppData\Local\Programs\Microsoft VS Code\bin; | ||
``` | ||
- **Note**: For some reason, the `$Env:Path` does not always update instantly (without reboot/relogin), even if the `[Environment]::GetEnvironmentVariable('Path', ...)` are updated. | ||
|
||
### Setting PATH (User) variables | ||
|
||
- User PATH before edits: [Screenshot](img/before-setting-user.png) | ||
- Adding a folder to PATH | ||
|
||
```python | ||
In [1]: from pathtub import add_to_path | ||
|
||
In [2]: added = add_to_path(r'C:\My new folder\added to user PATH') | ||
|
||
In [3]: added | ||
Out[3]: True | ||
|
||
# There is protection against adding duplicate entries | ||
In [4]: added = add_to_path(r'C:\My new folder\added to user PATH') | ||
|
||
In [5]: added | ||
Out[5]: False | ||
``` | ||
|
||
- User PATH after edits: [Screenshot](img/after-setting-user.png) | ||
|
||
|
||
|
||
### Setting PATH (System/Machine) variables | ||
- Similar to setting User PATH variables | ||
- Change mode to "machine" and *Run the script with Admin rights*. | ||
|
||
from pathtub import ensure | ||
dll_folder = r'C:\my favourite\dlls' | ||
# 1) Check Process PATH | ||
# 2) Add to Process PATH if not found | ||
# 3) Add also to User PATH (permanent), if 2) happens | ||
ensure(dll_folder, permanent=True) | ||
``` | ||
from pathtub import add_to_path | ||
added = add_to_path(r'C:\My new folder\added to machine PATH', mode='machine') | ||
- The Process PATH is loaded from parent process or from the permanent (User/System) PATH when process is started. For more info, see: [Windows PATH variables](docs/path_variables.md). | ||
- ["Real life" example using ensure](docs/example_ensure.md). | ||
- Full documentation of `ensure()` is in the source code ([pathtools.py](pathtub/pathtools.py)). | ||
### 🧽 Cleaning PATH | ||
#### Cleaning paths means | ||
1. Removing duplicates from the PATH (trailing backslash neglected) | ||
2. Removing empty entries from PATH | ||
3. Sorting alphabetically (optional, Default: True) | ||
4. Removing folders that do not exist (optional, Default: True) | ||
5. Removing from "User" list the ones that are in the "System" list (optional, default: True) | ||
|
||
#### Screenshots of User PATH before and after clean: | ||
![User PATH](img/user-before-after-clean.png) | ||
|
||
#### Code example for clean | ||
``` | ||
from pathtub import clean | ||
clean() | ||
### Removing PATH (User) variables | ||
|
||
```python | ||
In [1]: from pathtub import remove_from_path | ||
|
||
In [2]: removed = remove_from_path(r'C:\My new folder\added to user PATH') | ||
|
||
In [3]: removed | ||
Out[3]: True | ||
|
||
# Can only remove once. Safe to call multiple times. | ||
In [4]: removed = remove_from_path(r'C:\My new folder\added to user PATH') | ||
|
||
In [5]: removed | ||
Out[5]: False | ||
``` | ||
|
||
|
||
### Removing PATH (System/Machine) variables | ||
- Similar to removing User PATH variables | ||
- Change mode to "machine" and *Run the script with Admin rights*. | ||
|
||
# possible parameters: | ||
# clean(sort=True, remove_non_existent=True, remove_user_duplicates=True) | ||
``` | ||
from pathtub import add_to_path | ||
removed = remove_from_path(r'C:\My new folder\added to machine PATH', mode='machine') | ||
``` | ||
### Checking if folder is in PATH | ||
- **Note**: You don't have to worry if the saved PATH item ends with a backslash or not; both cases are checked. | ||
```python | ||
# Check the `$Env:Path` (Powershell) / `PATH` (cmd) variable | ||
found = is_in_path() # same as is_in_path("path") | ||
|
||
# Checks the `[Environment]::GetEnvironmentVariable('Path','User')`; The "User PATH" | ||
found_user = is_in_path("user") | ||
|
||
# Checks the `[Environment]::GetEnvironmentVariable('Path','Machine')`; The "System PATH" | ||
found = is_in_path("machine") | ||
``` | ||
#### Example | ||
```python | ||
In [1]: from pathtub import is_in_path | ||
|
||
In [2]: found = is_in_path('C:\\Python\\Python37\\', 'user') | ||
|
||
In [3]: found | ||
Out[3]: True | ||
|
||
# It does not matter if the seach folder or the folder saved | ||
# to PATH has "\" as the last character. | ||
In [4]: found = is_in_path(r'C:\Python\Python37', 'user') | ||
|
||
In [5]: found | ||
Out[5]: True | ||
|
||
In [6]: found = is_in_path(r'C:\Nonexistent\path', 'user') | ||
- For more detailed example, see [Full example of pathtub.clean](docs/example_clean.md) | ||
|
||
In [7]: found | ||
Out[7]: False | ||
``` | ||
### Rest of the docs | ||
Did not find what you were looking for? See the [Rest of the docs](docs/rest_of_the_docs.md). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
## Full example of `pathtub.clean` | ||
|
||
- Running the code below two times: <br> | ||
**Run #1**: ⛔👮 Without admin rights 👉 Only edit **User PATH**<br> | ||
**Run #2**: ✅👮 With admin rights 👉 Also edit **System PATH** | ||
|
||
```python | ||
from pathtub import clean | ||
clean() | ||
``` | ||
|
||
<details><summary>Output from Run #1 (⛔👮 Without admin rights)</summary> | ||
<p> | ||
|
||
``` | ||
Removing folder C:\Program Files\Sublime Text 3 from User Path (non-existing) | ||
Removing folder C:\Programs\phantomjs-2.1.1-windows\bin from User Path (non-existing) | ||
Removing folder C:\Programs\chromedriver_win32 from User Path (non-existing) | ||
Removing folder C:\Program Files (x86)\Microsoft SQL Server\150\DTS\Binn from User Path (non-existing) | ||
Removing folder C:\Python\Python37-32\Scripts from User Path (non-existing) | ||
Removing folder C:\Python\Python37-32 from User Path (non-existing) | ||
Removing folder C:\Program Files\Microsoft VS Code\bin from User Path (non-existing) | ||
Removing folder C:\Program Files\Sublime Text 3 from System Path (non-existing) | ||
Removing folder C:\Programs\phantomjs-2.1.1-windows\bin from System Path (non-existing) | ||
Removing folder C:\Programs\chromedriver_win32 from System Path (non-existing) | ||
Removing folder C:\Program Files (x86)\Microsoft SQL Server\150\DTS\Binn from System Path (non-existing) | ||
Removing folder C:\Program Files (x86)\Common Files\Oracle\Java\javapath from User Path (Defined in both; User and System PATH) | ||
Removing folder C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common from User Path (Defined in both; User and System PATH) | ||
Removing folder C:\ProgramData\Oracle\Java\javapath from User Path (Defined in both; User and System PATH) | ||
Removing folder C:\WINDOWS\system32 from User Path (Defined in both; User and System PATH) | ||
Removing folder C:\WINDOWS from User Path (Defined in both; User and System PATH) | ||
Removing folder C:\WINDOWS\System32\Wbem from User Path (Defined in both; User and System PATH) | ||
Removing folder C:\WINDOWS\System32\WindowsPowerShell\v1.0 from User Path (Defined in both; User and System PATH) | ||
Removing folder C:\Program Files (x86)\IVI Foundation\VISA\WinNT\Bin from User Path (Defined in both; User and System PATH) | ||
Removing folder C:\Program Files\IVI Foundation\VISA\Win64\Bin from User Path (Defined in both; User and System PATH) | ||
Removing folder C:\Program Files\Git\cmd from User Path (Defined in both; User and System PATH) | ||
Removing folder C:\Program Files (x86)\Windows Kits\8.1\Windows Performance Toolkit from User Path (Defined in both; User and System PATH) | ||
Removing folder C:\PostgreSQL\pg96\bin from User Path (Defined in both; User and System PATH) | ||
Removing folder C:\Program Files\nodejs from User Path (Defined in both; User and System PATH) | ||
Removing folder C:\Program Files\RabbitMQ Server\rabbitmq_server-3.6.12\sbin from User Path (Defined in both; User and System PATH) | ||
Removing folder C:\Users\USER\repos\git-subrepo\lib from User Path (Defined in both; User and System PATH) | ||
Removing folder C:\Program Files\MATLAB\R2018b\bin from User Path (Defined in both; User and System PATH) | ||
Removing folder C:\Program Files\TortoiseSVN\bin from User Path (Defined in both; User and System PATH) | ||
Removing folder C:\Program Files\dotnet from User Path (Defined in both; User and System PATH) | ||
Removing folder C:\Program Files (x86)\PuTTY from User Path (Defined in both; User and System PATH) | ||
Removing folder C:\WINDOWS\System32\OpenSSH from User Path (Defined in both; User and System PATH) | ||
Removing folder C:\Program Files\Intel\WiFi\bin from User Path (Defined in both; User and System PATH) | ||
Removing folder C:\Program Files\Common Files\Intel\WirelessCommon from User Path (Defined in both; User and System PATH) | ||
Removing folder C:\Program Files\CrashPlan\jre\bin\server from User Path (Defined in both; User and System PATH) | ||
Removing folder C:\Program Files\CrashPlan\jre\bin from User Path (Defined in both; User and System PATH) | ||
Could not clean the SYSTEM PATH! Needs Admin rights! | ||
``` | ||
</p> | ||
</details> | ||
|
||
<details><summary>Output from Run #2 (✅👮 With admin rights)</summary> | ||
<p> | ||
|
||
``` | ||
Removing folder C:\Program Files\Sublime Text 3 from System Path (non-existing) | ||
Removing folder C:\Programs\phantomjs-2.1.1-windows\bin from System Path (non-existing) | ||
Removing folder C:\Programs\chromedriver_win32 from System Path (non-existing) | ||
Removing folder C:\Program Files (x86)\Microsoft SQL Server\150\DTS\Binn from System Path (non-existing) | ||
``` | ||
</p> | ||
</details> | ||
<br> | ||
|
||
- Screenshots of User PATH before and after clean: | ||
![User PATH](../img/user-before-after-clean.png) | ||
- Screenshots of System PATH before and after clean (with admin rights): | ||
![System PATH](../img/system-before-after-clean.png) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
# Example of using `pathtub.ensure` | ||
|
||
## Description of problem | ||
- Want to use [pyusb](https://github.com/pyusb/pyusb), and need to ensure that it finds the [libusb-1.0.dll](https://github.com/libusb/libusb/releases). | ||
- Therefore, a folder containing the `libusb-1.0.dll` must be added to the PATH. | ||
|
||
### Trying without adding DLL folder | ||
|
||
- `get_backend()` returns no backends, since `libusb-1.0.dll` is not in the PATH | ||
```python | ||
import usb.backend.libusb1 | ||
|
||
#True | ||
usb.backend.libusb1.get_backend() is None | ||
``` | ||
- Also this throws a `LibraryNotFoundException` | ||
```python | ||
usb.backend.libusb1._load_library() | ||
``` | ||
|
||
``` | ||
# --------------------------------------------------------------------------- | ||
# LibraryNotFoundException Traceback (most recent call last) | ||
# ... | ||
# C:\Python\Python37\lib\site-packages\usb\libloader.py in load_locate_library(candidates, cygwin_lib, name, win_cls, cygwin_cls, others_cls, find_library, check_symbols) | ||
# 171 else: | ||
# 172 _LOGGER.error('%r could not be found', (name or candidates)) | ||
# --> 173 raise LibraryNotFoundException(name) | ||
# 174 else: | ||
# 175 raise NoLibraryCandidatesException(name) | ||
# LibraryNotFoundException: Libusb 1 | ||
``` | ||
|
||
### Adding DLL folder to PATH (current process) | ||
|
||
- Running now `pathtub.ensure` before calling the `usb.backend.libusb1` functions, and the `libusb-1.0.dll` is found correctly. | ||
- It is safe to leave the `ensure` command to the script. Running it multiple times does not do any harm; it just checks the `os.environ['PATH']`. | ||
```python | ||
from pathtub import ensure | ||
import usb.backend.libusb1 | ||
|
||
# Folder that contains libusb-1.0.dll | ||
dll_folder = r'C:\My favourite folder\libusb\dll' | ||
|
||
ensure(dll_folder) | ||
|
||
# <usb.backend.libusb1._LibUSB at 0x23abb47bb38> | ||
usb.backend.libusb1.get_backend() | ||
|
||
#<WinDLL 'C:\My favourite folder\libusb\dll\libusb-1.0.dll', handle 7fffe9240000 at 0x23abb05e470> | ||
usb.backend.libusb1._load_library() | ||
|
||
``` | ||
|
||
|
||
### Adding DLL folder to PATH (permanently) | ||
|
||
- By default, the `ensure` adds the DLL folder to the Process PATH, which means *only current python process will be able to see it*. | ||
- To add the DLL folder to the `User PATH` (see: [Windows PATH variables](path_variables.md).), and make `libusb-1.0.dll` available for all processes spawned afterwards, we use the `permanent` parameter. | ||
- It is safe to leave the `ensure(dll_folder, permanent=True)` command to the script. Running it multiple times does not do any harm; it just checks the `os.environ['PATH']`. | ||
|
||
```python | ||
from pathtub import ensure | ||
import usb.backend.libusb1 | ||
|
||
# Folder that contains libusb-1.0.dll | ||
dll_folder = r'C:\My favourite folder\libusb\dll' | ||
|
||
# Addition: permanent=True | ||
ensure(dll_folder, permanent=True) | ||
|
||
# <usb.backend.libusb1._LibUSB at 0x23abb47bb38> | ||
usb.backend.libusb1.get_backend() | ||
|
||
#<WinDLL 'C:\My favourite folder\libusb\dll\libusb-1.0.dll', handle 7fffe9240000 at 0x23abb05e470> | ||
usb.backend.libusb1._load_library() | ||
|
||
``` | ||
- **Note**: If you have the DLL_folder already in the Process PATH of the current process, then `ensure(dll_folder, permanent=True)` will skip adding it to the (permanent) User Path. You may also use | ||
- `ensure(dll_folder, permanent=True, force=True)` or | ||
- `pathtub.add_to_path(dll_folder, 'user')` | ||
- Note also that forcing adding to the permanent path each time a script is ran is not recommended since it takes some time. Consider the above as one-time-script. | ||
|
Oops, something went wrong.