# Slushie π§
π Ever wanted to just get a file from a sibling or parent directory without pulling your hair out? Slushie is the perfect "it just works" solution to relative paths in Python.
<!-- include media/slushie.gif -->
![Slushie Demo](media/slushie.gif)
## Table of Contents
- [β Why Slushie?](#-why-slushie)
- [π Installation](#-installation)
- [π Usage](#-usage)
- [π¬ Running Tests](#-running-tests)
- [π€ Contributing](#-contributing)
- [π License](#-license)
## β Why Slushie?
Relative paths and imports in Python are an absolute nightmare due to how `PYTHONPATH` works and finds modules.
For example,
```
project_root/
β main.py
β
ββββpackage1/
β β module1.py
β β file.csv
β β
β ββββsubpackage1/
β β module2.py
```
If I wanted to import `module1.py` from `main.py`, you'd think it would be something like the following:
```
from package1 import module1
from package1.subpackage1 import module2
```
<!-- bold -->
**This (most likely) will not work. Why?**
Python relies on the dreaded `PYTHONPATH` environment variable to determine where to look for modules to import.
`PYTHONPATH` is a list of directories that Python checks whenever you attempt an import. If `package1` and `subpackage1` are not included in the `PYTHONPATH`, Python doesnβt know where to look for `module1.py`, and `module2.py`, resulting in an `ImportError`.
Additionally, attempting to open `file.csv`, using the traditional open command like this:
```
open("package1/file.csv")
```
will most likely not even find the file, and even if it does, there's a high chance it will break if it is ever moved to another machine or ran from a different directory.
This is because the search for `file.csv` is relative to the current working directory where the Python script is executed, not necessarily where main.py is located.
**TL;DR: If you use python's default import and open commands, you either have to do some Python witchcraft or risk randomly breaking your code.**
## π Installation
Install it directly from PyPI:
```
pip install slushie
```
## π Usage
### sip(*parts: str) -> str
**Purpose**: Create absolute paths relative to the current FILE. Ideal for accessing files in parent or sibling directories without a fuss.
#### Parameters:
- `*parts: str` - Parts of the path to join.
#### Usage:
Access `hello.txt` located in a sibling directory from `script.py`.
```
/project
/folder1
script.py
/folder2
hello.txt
```
```python
path = sip('..', 'folder2', 'hello.txt')
print(path)
# Output:
# /path/to/project/folder2/hello.txt
# In this case, sip('.') refers to /path/to/project/folder1/
```
The above code is fundamentally equivalent to the following:
```python
import os
import sys
path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'folder2', 'hello.txt')
print(path)
# Output:
# /path/to/project/folder2/hello.txt
```
This is extremely useful, as if you ever need to open a file, such as a csv for data analysis or a text file for logging, you should almost always be using relative paths as to avoid breaking your code when you move it to a different machine or share it with someone else. Slushie makes this easy.
```python
### gulp(directory: str = '.') -> Iterator[None]
**Purpose**: Temporarily include directories in the Python path, easing the import of modules/packages.
#### Parameters:
- `directory: str` - Directory to add directories from.
#### Usage:
Import a module from a sibling directory.
```python
with gulp('../sibling_directory'):
import a_module_from_sibling_directory
```
### freeze(path: str) -> None
**Purpose**: Make a specific directory permanently available for imports.
#### Parameters:
- `path: str` - Path to append to `sys.path`.
#### Usage:
```python
freeze('../another_directory')
import a_module_from_another_directory
```
### pour(directory: str = '.') -> Iterator[Tuple[str, str]]
**Purpose**: Easily access the current and parent directory paths of the current file the code is being written in.
#### Parameters:
- `directory: str` - Directory to get paths for.
#### Usage:
```python
with pour() as (current_dir, parent_dir):
print(f"Current Directory: {current_dir}")
print(f"Parent Directory: {parent_dir}")
```
### melt() -> str
**Purpose**: Find the directory of the calling script, aiding in understanding the execution context.
#### Usage:
```python
caller_path = melt()
print(f"Caller Path: {caller_path}")
# Output:
# Caller Path: /path/to/calling/script.py
# This is the path of the script that called melt(), not the path of melt() itself.
# So if I had script /path/to/calling/script.py that called melt(), and melt() was located at /path/to/melt.py, the output would still be:
# Caller Path: /path/to/calling/script.py
```
### slurp() -> str
**Purpose**: Identify where the terminal command was executed from.
#### Usage:
```python
terminal_path = slurp()
print(f"Terminal Path: {terminal_path}")
# So if the script was located at /path/to/script.py and the terminal command was executed from /path/to, the output would be:
# Terminal Path: /path/to
```
### scoop(file: str, mode: str = 'r', ...) -> TextIO
**Purpose**: Simplify opening files by managing paths relative to the current script automatically.
#### Parameters:
Literally the same as the built-in `open()` function. It's just a wrapper around it that automatically manages paths relative to the current script.
#### Usage:
```python
with scoop('../data.txt', 'r') as file:
data = file.read()
print(data)
```
## π¬ Running Tests
Keeping Slushie frosty with some cool tests:
- **For Linux:**
```
./run_tests.sh
```
- **For Windows:**
```
run_tests.bat
```
## π€ Contributing
Contribute your own flavors to make Slushie even more delightful! π
## π License
Slushie is lovingly served under the MIT License. Scoop into the [LICENSE](LICENSE) file for the full details.
Raw data
{
"_id": null,
"home_page": "https://github.com/saleguas/slushie",
"name": "slushie",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3",
"maintainer_email": "",
"keywords": "path sys-path manipulation python-path module-path",
"author": "Salvador Aleguas",
"author_email": "salvadoraleguas@example.com",
"download_url": "https://files.pythonhosted.org/packages/5a/ae/bb554bb42dd7c85e8443344f32f12198e5fcb527119f9d40289c71e17936/slushie-0.2.4.tar.gz",
"platform": null,
"description": "# Slushie \ud83c\udf67\r\n\r\n\ud83c\udf6d Ever wanted to just get a file from a sibling or parent directory without pulling your hair out? Slushie is the perfect \"it just works\" solution to relative paths in Python.\r\n\r\n<!-- include media/slushie.gif -->\r\n\r\n![Slushie Demo](media/slushie.gif)\r\n\r\n## Table of Contents\r\n\r\n- [\u2754 Why Slushie?](#-why-slushie)\r\n- [\ud83d\ude80 Installation](#-installation)\r\n- [\ud83c\udf08 Usage](#-usage)\r\n- [\ud83d\udd2c Running Tests](#-running-tests)\r\n- [\ud83e\udd1d Contributing](#-contributing)\r\n- [\ud83d\udcdc License](#-license)\r\n\r\n## \u2754 Why Slushie?\r\n\r\nRelative paths and imports in Python are an absolute nightmare due to how `PYTHONPATH` works and finds modules.\r\n\r\nFor example, \r\n```\r\nproject_root/\r\n\u2502 main.py\r\n\u2502\r\n\u251c\u2500\u2500\u2500package1/\r\n\u2502 \u2502 module1.py\r\n\u2502 \u2502 file.csv\r\n\u2502 \u2502\r\n\u2502 \u2514\u2500\u2500\u2500subpackage1/\r\n\u2502 \u2502 module2.py\r\n```\r\n\r\nIf I wanted to import `module1.py` from `main.py`, you'd think it would be something like the following:\r\n\r\n```\r\nfrom package1 import module1\r\nfrom package1.subpackage1 import module2\r\n```\r\n\r\n<!-- bold -->\r\n\r\n**This (most likely) will not work. Why?**\r\n\r\nPython relies on the dreaded `PYTHONPATH` environment variable to determine where to look for modules to import. \r\n\r\n`PYTHONPATH` is a list of directories that Python checks whenever you attempt an import. If `package1` and `subpackage1` are not included in the `PYTHONPATH`, Python doesn\u2019t know where to look for `module1.py`, and `module2.py`, resulting in an `ImportError`.\r\n\r\nAdditionally, attempting to open `file.csv`, using the traditional open command like this:\r\n\r\n```\r\nopen(\"package1/file.csv\")\r\n```\r\n\r\nwill most likely not even find the file, and even if it does, there's a high chance it will break if it is ever moved to another machine or ran from a different directory.\r\n\r\nThis is because the search for `file.csv` is relative to the current working directory where the Python script is executed, not necessarily where main.py is located.\r\n\r\n**TL;DR: If you use python's default import and open commands, you either have to do some Python witchcraft or risk randomly breaking your code.**\r\n\r\n## \ud83d\ude80 Installation\r\n\r\nInstall it directly from PyPI:\r\n\r\n```\r\npip install slushie\r\n```\r\n\r\n## \ud83c\udf08 Usage\r\n\r\n\r\n### sip(*parts: str) -> str\r\n\r\n**Purpose**: Create absolute paths relative to the current FILE. Ideal for accessing files in parent or sibling directories without a fuss.\r\n\r\n#### Parameters:\r\n- `*parts: str` - Parts of the path to join.\r\n\r\n#### Usage:\r\nAccess `hello.txt` located in a sibling directory from `script.py`.\r\n\r\n```\r\n/project\r\n /folder1\r\n script.py\r\n /folder2\r\n hello.txt\r\n```\r\n\r\n```python\r\npath = sip('..', 'folder2', 'hello.txt')\r\nprint(path)\r\n\r\n# Output:\r\n# /path/to/project/folder2/hello.txt\r\n# In this case, sip('.') refers to /path/to/project/folder1/\r\n```\r\n\r\nThe above code is fundamentally equivalent to the following:\r\n\r\n```python\r\nimport os\r\nimport sys\r\n\r\npath = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'folder2', 'hello.txt')\r\nprint(path)\r\n\r\n# Output:\r\n# /path/to/project/folder2/hello.txt\r\n```\r\n\r\nThis is extremely useful, as if you ever need to open a file, such as a csv for data analysis or a text file for logging, you should almost always be using relative paths as to avoid breaking your code when you move it to a different machine or share it with someone else. Slushie makes this easy.\r\n\r\n```python\r\n### gulp(directory: str = '.') -> Iterator[None]\r\n\r\n**Purpose**: Temporarily include directories in the Python path, easing the import of modules/packages.\r\n\r\n#### Parameters:\r\n- `directory: str` - Directory to add directories from.\r\n\r\n#### Usage:\r\nImport a module from a sibling directory.\r\n\r\n```python\r\nwith gulp('../sibling_directory'):\r\n import a_module_from_sibling_directory\r\n```\r\n\r\n### freeze(path: str) -> None\r\n\r\n**Purpose**: Make a specific directory permanently available for imports.\r\n\r\n#### Parameters:\r\n- `path: str` - Path to append to `sys.path`.\r\n\r\n#### Usage:\r\n```python\r\nfreeze('../another_directory')\r\nimport a_module_from_another_directory\r\n```\r\n\r\n### pour(directory: str = '.') -> Iterator[Tuple[str, str]]\r\n\r\n**Purpose**: Easily access the current and parent directory paths of the current file the code is being written in.\r\n\r\n#### Parameters:\r\n- `directory: str` - Directory to get paths for.\r\n\r\n#### Usage:\r\n```python\r\nwith pour() as (current_dir, parent_dir):\r\n print(f\"Current Directory: {current_dir}\")\r\n print(f\"Parent Directory: {parent_dir}\")\r\n```\r\n\r\n### melt() -> str\r\n\r\n**Purpose**: Find the directory of the calling script, aiding in understanding the execution context.\r\n\r\n#### Usage:\r\n```python\r\ncaller_path = melt()\r\nprint(f\"Caller Path: {caller_path}\")\r\n\r\n# Output:\r\n# Caller Path: /path/to/calling/script.py\r\n# This is the path of the script that called melt(), not the path of melt() itself.\r\n# So if I had script /path/to/calling/script.py that called melt(), and melt() was located at /path/to/melt.py, the output would still be:\r\n# Caller Path: /path/to/calling/script.py\r\n```\r\n\r\n\r\n### slurp() -> str\r\n\r\n**Purpose**: Identify where the terminal command was executed from.\r\n\r\n#### Usage:\r\n```python\r\nterminal_path = slurp()\r\nprint(f\"Terminal Path: {terminal_path}\")\r\n\r\n# So if the script was located at /path/to/script.py and the terminal command was executed from /path/to, the output would be:\r\n# Terminal Path: /path/to\r\n```\r\n\r\n### scoop(file: str, mode: str = 'r', ...) -> TextIO\r\n\r\n**Purpose**: Simplify opening files by managing paths relative to the current script automatically.\r\n\r\n#### Parameters:\r\nLiterally the same as the built-in `open()` function. It's just a wrapper around it that automatically manages paths relative to the current script.\r\n\r\n\r\n#### Usage:\r\n```python\r\nwith scoop('../data.txt', 'r') as file:\r\n data = file.read()\r\n print(data)\r\n```\r\n\r\n## \ud83d\udd2c Running Tests\r\n\r\nKeeping Slushie frosty with some cool tests:\r\n\r\n- **For Linux:**\r\n ```\r\n ./run_tests.sh\r\n ```\r\n\r\n- **For Windows:**\r\n ```\r\n run_tests.bat\r\n ```\r\n\r\n## \ud83e\udd1d Contributing\r\n\r\nContribute your own flavors to make Slushie even more delightful! \ud83c\udf08\r\n\r\n## \ud83d\udcdc License\r\n\r\nSlushie is lovingly served under the MIT License. Scoop into the [LICENSE](LICENSE) file for the full details.\r\n\r\n\r\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Slushie: A Python library for relative path manipulation.",
"version": "0.2.4",
"project_urls": {
"Homepage": "https://github.com/saleguas/slushie"
},
"split_keywords": [
"path",
"sys-path",
"manipulation",
"python-path",
"module-path"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "f2754fbaf64543d6b455ad4f03cb64b72886bab5f2be5398416bc01e9d4db76d",
"md5": "40bd582441594c391e79993637e6909a",
"sha256": "3cc853e23ac25d04a88a8c585b1450b69e76c559ef49d3e9cff6e065e8ae5667"
},
"downloads": -1,
"filename": "slushie-0.2.4-py3-none-any.whl",
"has_sig": false,
"md5_digest": "40bd582441594c391e79993637e6909a",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3",
"size": 6932,
"upload_time": "2023-11-19T23:20:16",
"upload_time_iso_8601": "2023-11-19T23:20:16.328509Z",
"url": "https://files.pythonhosted.org/packages/f2/75/4fbaf64543d6b455ad4f03cb64b72886bab5f2be5398416bc01e9d4db76d/slushie-0.2.4-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "5aaebb554bb42dd7c85e8443344f32f12198e5fcb527119f9d40289c71e17936",
"md5": "da9f8e73f77d19d0979aa1546592c529",
"sha256": "e912ea7624d83cf23aadcdd6e41bdac05a98bd35437d513ea67047ae0a65429e"
},
"downloads": -1,
"filename": "slushie-0.2.4.tar.gz",
"has_sig": false,
"md5_digest": "da9f8e73f77d19d0979aa1546592c529",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3",
"size": 6572,
"upload_time": "2023-11-19T23:20:18",
"upload_time_iso_8601": "2023-11-19T23:20:18.432853Z",
"url": "https://files.pythonhosted.org/packages/5a/ae/bb554bb42dd7c85e8443344f32f12198e5fcb527119f9d40289c71e17936/slushie-0.2.4.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-11-19 23:20:18",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "saleguas",
"github_project": "slushie",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "slushie"
}