Skip to content

Commit 7c776fc

Browse files
committed
feat: initial base dirs sketch, avoid computed fields
1 parent d6a2ed7 commit 7c776fc

4 files changed

Lines changed: 139 additions & 41 deletions

File tree

smartdirs/__init__.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@
55
WORKSPACE: str = "WORKSPACE"
66
"""Variable for setting a common directories root"""
77

8+
# Warn: Use base class for isinstance() checks!
89
from smartdirs.base import SmartDirsBase
910
from smartdirs.flavor.macos import SmartDirsMacOS
1011
from smartdirs.flavor.unix import SmartDirsUnix
1112
from smartdirs.flavor.windows import SmartDirsWindows
1213
from smartdirs.flavor.workspace import SmartDirsWorkspace
1314

1415
# Global dispatch branch on flavors
15-
if os.environ.get(WORKSPACE, None):
16+
if (WORKSPACE in os.environ):
1617
SmartDirs = SmartDirsWorkspace
1718

1819
elif os.name == "posix":
@@ -31,7 +32,7 @@
3132

3233
dirs = SmartDirs(
3334
package=Path(__file__).parent,
34-
name=str(__package__),
35-
vendor="brokensource",
35+
app=str(__package__),
36+
org="tremeschin",
3637
)
3738
"""A main SmartDirs instance so you can get static/base directories"""

smartdirs/base.py

Lines changed: 95 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import tempfile
12
from abc import ABC, abstractmethod
3+
from collections.abc import Callable
24
from pathlib import Path
35

4-
from pydantic import BaseModel, Field, computed_field
6+
from pydantic import BaseModel, Field, model_serializer
57

68

79
class UserOptions(BaseModel):
@@ -14,58 +16,126 @@ class SmartDirsBase(BaseModel, ABC):
1416
package: Path
1517
"""Path to the package root"""
1618

17-
name: str = Field()
19+
app: str = Field()
1820
"""Application name for directories"""
1921

20-
vendor: str = Field()
22+
org: str = Field()
2123
"""Author or vendor name for directories"""
2224

25+
@property
26+
def repository(self) -> Path:
27+
"""Path to the repository root"""
28+
return self.package.parent
29+
30+
@property
31+
def tempdir(self) -> Path:
32+
return Path(tempfile.gettempdir())
33+
2334
# ------------------------------------------------------------------------ #
2435

25-
@computed_field
2636
@property
2737
def resources(self) -> Path:
2838
"""Path to the resources directory"""
2939
return self.package.joinpath("resources")
3040

31-
@property
32-
def repository(self) -> Path:
33-
"""Path to the repository root"""
34-
return self.package.parent
35-
3641
# ------------------------------------------------------------------------ #
3742

38-
@computed_field
3943
@abstractmethod
4044
def base_home(self) -> Path:
4145
"""
42-
Path to the user's home directory
43-
| Where | Value | Example |
44-
| :-------- | :----------------- | :--------------- |
45-
| Linux | $HOME | /home/alice |
46-
| macOS | $HOME | /Users/Alice |
47-
| Windows | {FOLDERID_Profile} | C:\\Users\\Alice |
48-
| Workspace | $WORKSPACE | - |
46+
| Where | Value | Example |
47+
| :-------- | :------------------- | :----------------- |
48+
| Linux | `$HOME` | `/home/alice` |
49+
| macOS | `$HOME` | `/Users/Alice` |
50+
| Windows | `{FOLDERID_Profile}` | `C:\\Users\\Alice` |
51+
| Workspace | `$WORKSPACE` | `/workspace` |
4952
"""
5053

51-
@computed_field
5254
@abstractmethod
5355
def base_cache(self) -> Path:
5456
"""
55-
- Linux: $XDG_CACHE_HOME or $HOME/.cache
56-
- macOS: $HOME/Library/Caches
57-
- MsWin: {FOLDERID_LocalAppData}
57+
| Where | Value | Example |
58+
| :-------- | :------------------------------------- | :--------------------------------- |
59+
| Linux | `$XDG_CACHE_HOME` or `$HOME/.cache` | `/home/alice/.config` |
60+
| macOS | `$HOME/Library/Caches` | `/Users/Alice/Library/Caches` |
61+
| Windows | `{FOLDERID_LocalAppData}` | `C:\\Users\\Alice\\AppData\\Local` |
62+
| Workspace | `$WORKSPACE/base/cache` | `/workspace/base/cache` |
5863
"""
5964

60-
@computed_field
6165
@abstractmethod
6266
def base_config(self) -> Path:
6367
"""
64-
- Linux: $XDG_CONFIG_HOME or $HOME/.config
65-
- macOS: $HOME/Library/Application Support
66-
- MsWin: {FOLDERID_RoamingAppData}
68+
| Where | Value | Example |
69+
| :-------- | :------------------------------------- | :--------------------------------- |
70+
| Linux | `$XDG_CACHE_HOME` or `$HOME/.cache` | `/home/alice/.config` |
71+
| macOS | `$HOME/Library/Caches` | `/Users/Alice/Library/Caches` |
72+
| Windows | `{FOLDERID_LocalAppData}` | `C:\\Users\\Alice\\AppData\\Local` |
73+
| Workspace | `$WORKSPACE/base/cache` | `/workspace/base/cache` |
74+
"""
75+
76+
@abstractmethod
77+
def base_data(self) -> Path:
78+
"""
79+
Persistent data storage for applications.
80+
| Where | Value | Example |
81+
| :-------- | :--------------------------------------- | :----------------------------------------- |
82+
| Linux | `$XDG_DATA_HOME` or `$HOME/.local/share` | `/home/alice/.local/share` |
83+
| macOS | `$HOME/Library/Application Support` | `/Users/Alice/Library/Application Support` |
84+
| Windows | `{FOLDERID_RoamingAppData}` | `C:\\Users\\Alice\\AppData\\Local` |
85+
| Workspace | `$WORKSPACE/base/data` | `/workspace/base/data` |
86+
"""
87+
88+
@abstractmethod
89+
def base_runtime(self) -> Path:
90+
"""
91+
Live application data that resets on reboot, similar to /tmp but only user-writable.
92+
| Where | Value | Example |
93+
| :-------- | :----------------------------------------- | :--------------- |
94+
| Linux | `$XDG_RUNTIME_DIR` or `/run/user/${id -u}` | `/run/user/1000` |
95+
| macOS | `None` | `None` |
96+
| Windows | `None` | `None` |
97+
| Workspace | Same for host platform | dynamic |
98+
"""
99+
100+
# ------------------------------------------------------------------------ #
101+
102+
@abstractmethod
103+
def app_subdir(self) -> Path:
104+
...
105+
106+
@abstractmethod
107+
def app_runtime(self) -> Path:
108+
"""
109+
Live application data that resets on reboot, similar to /tmp but only user-writable.
110+
| Where | Value | Example |
111+
| :-------- | :----------------------------------------- | :--------------- |
112+
| Linux | `$XDG_RUNTIME_DIR` or `/run/user/${id -u}` | `/run/user/1000` |
113+
| macOS | `None` | `None` |
114+
| Windows | `None` | `None` |
115+
| Workspace | Same for host platform | dynamic |
67116
"""
68117

69118
# ------------------------------------------------------------------------ #
70119

71120
user: UserOptions = UserOptions()
121+
122+
# ------------------------------------------------------------------------ #
123+
124+
@model_serializer(mode="wrap")
125+
def serialize(self, handler):
126+
data = handler(self)
127+
128+
def export(*methods: Callable):
129+
return {get.__name__: get() for get in methods} # type: ignore
130+
131+
data.update(export(
132+
self.base_home,
133+
self.base_cache,
134+
self.base_config,
135+
self.base_data,
136+
self.base_runtime,
137+
self.app_subdir,
138+
self.app_runtime,
139+
))
140+
141+
return data

smartdirs/flavor/unix.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,44 @@
11
import os
22
from pathlib import Path
33

4-
from pydantic import computed_field
5-
64
from smartdirs.base import SmartDirsBase
75

86

97
class SmartDirsUnix(SmartDirsBase):
108

11-
@computed_field
9+
# ------------------------------------------------------------------------ #
10+
1211
def base_home(self) -> Path:
1312
return Path.home()
1413

15-
@computed_field
1614
def base_cache(self) -> Path:
1715
return Path(os.environ.get(
1816
key="XDG_CACHE_HOME",
1917
default=Path.home().joinpath(".cache"),
2018
))
2119

22-
@computed_field
2320
def base_config(self) -> Path:
2421
return Path(os.environ.get(
2522
key="XDG_CONFIG_HOME",
2623
default=Path.home().joinpath(".config"),
2724
))
25+
26+
def base_data(self) -> Path:
27+
return Path(os.environ.get(
28+
key="XDG_DATA_HOME",
29+
default=Path.home().joinpath(".local", "share"),
30+
))
31+
32+
def base_runtime(self) -> Path:
33+
return Path(os.environ.get(
34+
key="XDG_RUNTIME_DIR",
35+
default=Path("/run/user", str(os.getuid()))
36+
))
37+
38+
# ------------------------------------------------------------------------ #
39+
40+
def app_subdir(self) -> Path:
41+
return Path(self.app)
42+
43+
def app_runtime(self) -> Path:
44+
return self.base_runtime().joinpath(self.app_subdir())

smartdirs/flavor/workspace.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,35 @@
11
import os
22
from pathlib import Path
33

4-
from pydantic import Field, computed_field
4+
from pydantic import Field
55

6+
import smartdirs
67
from smartdirs import WORKSPACE
78
from smartdirs.base import SmartDirsBase
89

910

1011
class SmartDirsWorkspace(SmartDirsBase):
1112
root: Path = Field(default_factory=lambda:
12-
Path(os.environ[WORKSPACE])
13-
)
13+
Path(os.environ[WORKSPACE]))
14+
15+
# ------------------------------------------------------------------------ #
1416

15-
@computed_field
1617
def base_home(self) -> Path:
1718
return self.root
1819

19-
@computed_field
2020
def base_cache(self) -> Path:
21-
return self.root.joinpath("cache")
21+
return self.root.joinpath("base", "cache")
2222

23-
@computed_field
2423
def base_config(self) -> Path:
25-
return self.root.joinpath("config")
24+
return self.root.joinpath("base", "config")
25+
26+
def base_data(self) -> Path:
27+
return self.root.joinpath("base", "data")
28+
29+
def base_runtime(self) -> Path:
30+
return smartdirs.SmartDirs.base_runtime(self)
31+
32+
# ------------------------------------------------------------------------ #
33+
34+
def app_subdir(self) -> Path:
35+
return Path(self.app)

0 commit comments

Comments
 (0)