flatbread 0.1.1__tar.gz → 0.1.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. {flatbread-0.1.1 → flatbread-0.1.2}/PKG-INFO +1 -1
  2. flatbread-0.1.2/flatbread/config.py +133 -0
  3. {flatbread-0.1.1 → flatbread-0.1.2}/pyproject.toml +1 -1
  4. flatbread-0.1.1/flatbread/config.py +0 -43
  5. {flatbread-0.1.1 → flatbread-0.1.2}/.gitignore +0 -0
  6. {flatbread-0.1.1 → flatbread-0.1.2}/environment.yml +0 -0
  7. {flatbread-0.1.1 → flatbread-0.1.2}/flatbread/__init__.py +0 -0
  8. {flatbread-0.1.1 → flatbread-0.1.2}/flatbread/accessors/dataframe.py +0 -0
  9. {flatbread-0.1.1 → flatbread-0.1.2}/flatbread/accessors/index.py +0 -0
  10. {flatbread-0.1.1 → flatbread-0.1.2}/flatbread/accessors/series.py +0 -0
  11. {flatbread-0.1.1 → flatbread-0.1.2}/flatbread/agg/aggregation.py +0 -0
  12. {flatbread-0.1.1 → flatbread-0.1.2}/flatbread/agg/totals.py +0 -0
  13. {flatbread-0.1.1 → flatbread-0.1.2}/flatbread/chaining.py +0 -0
  14. {flatbread-0.1.1 → flatbread-0.1.2}/flatbread/config/config.defaults.json +0 -0
  15. {flatbread-0.1.1 → flatbread-0.1.2}/flatbread/percentages.py +0 -0
  16. {flatbread-0.1.1 → flatbread-0.1.2}/flatbread/render/config.py +0 -0
  17. {flatbread-0.1.1 → flatbread-0.1.2}/flatbread/render/constants.py +0 -0
  18. {flatbread-0.1.1 → flatbread-0.1.2}/flatbread/render/display.py +0 -0
  19. {flatbread-0.1.1 → flatbread-0.1.2}/flatbread/render/tablespec.py +0 -0
  20. {flatbread-0.1.1 → flatbread-0.1.2}/flatbread/render/template.jinja.html +0 -0
  21. {flatbread-0.1.1 → flatbread-0.1.2}/flatbread/render/template.py +0 -0
  22. {flatbread-0.1.1 → flatbread-0.1.2}/flatbread/testing/dataframe.py +0 -0
  23. {flatbread-0.1.1 → flatbread-0.1.2}/flatbread/tooling.py +0 -0
  24. {flatbread-0.1.1 → flatbread-0.1.2}/license.md +0 -0
  25. {flatbread-0.1.1 → flatbread-0.1.2}/readme.md +0 -0
  26. {flatbread-0.1.1 → flatbread-0.1.2}/tests/__init__.py +0 -0
  27. {flatbread-0.1.1 → flatbread-0.1.2}/tests/aggregate/__init__.py +0 -0
  28. {flatbread-0.1.1 → flatbread-0.1.2}/tests/aggregate/test_percentages.py +0 -0
  29. {flatbread-0.1.1 → flatbread-0.1.2}/tests/aggregate/test_totals.py +0 -0
  30. {flatbread-0.1.1 → flatbread-0.1.2}/tests/test_axes.py +0 -0
  31. {flatbread-0.1.1 → flatbread-0.1.2}/tests/test_levels.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flatbread
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Summary: Pandas extension for aggregation and tabular display
5
5
  Project-URL: Homepage, https://github.com/lcvriend/flatbread
6
6
  Author-email: "L.C. Vriend" <vanboefer@gmail.com>
@@ -0,0 +1,133 @@
1
+ import functools
2
+ import json
3
+ from pathlib import Path
4
+ from typing import Callable
5
+
6
+
7
+ def deep_merge(base: dict, update: dict) -> dict:
8
+ """
9
+ Deep merge two dictionaries, preserving structure from both.
10
+
11
+ - When both dicts have a dict at the same key, merge recursively
12
+ - When update has keys not in base, add them
13
+ - When types mismatch (e.g., dict in one, value in other), prefer update
14
+
15
+ Parameters
16
+ ----------
17
+ base : dict
18
+ Base dictionary to merge into
19
+ update : dict
20
+ Dictionary with values to update base with
21
+
22
+ Returns
23
+ -------
24
+ dict
25
+ Merged dictionary
26
+ """
27
+ merged = base.copy()
28
+ for key, update_val in update.items():
29
+ if key not in merged:
30
+ # Add keys from update that don't exist in base
31
+ merged[key] = update_val
32
+ elif isinstance(update_val, dict) and isinstance(merged[key], dict):
33
+ # Recursively merge nested dictionaries
34
+ merged[key] = deep_merge(merged[key], update_val)
35
+ else:
36
+ # Override base value with update value
37
+ merged[key] = update_val
38
+ return merged
39
+
40
+
41
+ def find_project_config(max_levels: int = 5) -> Path|None:
42
+ """
43
+ Find project-level .flatbread.json, traversing up from current directory.
44
+
45
+ Parameters
46
+ ----------
47
+ max_levels : int, default 5
48
+ Maximum number of directory levels to traverse upward
49
+
50
+ Returns
51
+ -------
52
+ Path or None
53
+ Path to the config file if found, None otherwise
54
+ """
55
+ current_dir = Path.cwd()
56
+ home_dir = Path.home()
57
+
58
+ # Check current directory and up to max_levels parent directories
59
+ for _ in range(max_levels + 1):
60
+ config_path = current_dir / ".flatbread.json"
61
+ if config_path.is_file():
62
+ return config_path
63
+
64
+ # Stop if we've reached the filesystem root or home directory
65
+ if current_dir == current_dir.parent or current_dir == home_dir:
66
+ break
67
+
68
+ # Move up one directory
69
+ current_dir = current_dir.parent
70
+
71
+ return None
72
+
73
+
74
+ def read_config():
75
+ """
76
+ Read configuration with priority: project > user > defaults.
77
+
78
+ Returns
79
+ -------
80
+ dict
81
+ Merged configuration dictionary
82
+ """
83
+ # 1. Look for project config first
84
+ project_config = None
85
+ if project_path := find_project_config():
86
+ project_config = json.loads(project_path.read_text())
87
+
88
+ # 2. Look for user config
89
+ user_config = None
90
+ user_config_path = Path('~/.flatbread.json').expanduser()
91
+ if user_config_path.exists():
92
+ user_config = json.loads(user_config_path.read_text())
93
+
94
+ # 3. Get default config
95
+ package_path = Path(__file__).resolve().parent
96
+ config = json.loads((package_path / 'config/config.defaults.json').read_text())
97
+
98
+ # Merge configs with right precedence
99
+ if user_config:
100
+ config = deep_merge(config, user_config)
101
+ if project_config:
102
+ config = deep_merge(config, project_config)
103
+
104
+ return config
105
+
106
+
107
+ def inject_defaults(defaults: dict) -> Callable:
108
+ """
109
+ Load defaults if keywords are None or undefined when calling a function.
110
+
111
+ Arguments
112
+ ---------
113
+ defaults (dict):
114
+ Dictionary of keywords and default values.
115
+
116
+ Return
117
+ ------
118
+ func:
119
+ Function that will load defaults.
120
+
121
+ Notes
122
+ -----
123
+ This decorator will override any default values set in the function definition.
124
+ """
125
+ def decorator(func):
126
+ @functools.wraps(func)
127
+ def wrapper(*args, **kwargs):
128
+ for key, val in defaults.items():
129
+ if kwargs.get(key) is None:
130
+ kwargs[key] = val
131
+ return func(*args, **kwargs)
132
+ return wrapper
133
+ return decorator
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "flatbread"
7
- version = "0.1.1"
7
+ version = "0.1.2"
8
8
  description = "Pandas extension for aggregation and tabular display"
9
9
  readme = "readme.md"
10
10
  requires-python = ">=3.10"
@@ -1,43 +0,0 @@
1
- import functools
2
- import json
3
- from pathlib import Path
4
- from typing import Callable
5
-
6
-
7
- def read_config():
8
- config_path = Path('~/.flatbread/config.json').expanduser()
9
- if not config_path.exists():
10
- package_path = Path(__file__).resolve().parent
11
- config_path = package_path / 'config/config.defaults.json'
12
- json_string = config_path.read_text()
13
- config = json.loads(json_string)
14
- return config
15
-
16
-
17
- def inject_defaults(defaults: dict) -> Callable:
18
- """
19
- Load defaults if keywords are None or undefined when calling a function.
20
-
21
- Arguments
22
- ---------
23
- defaults (dict):
24
- Dictionary of keywords and default values.
25
-
26
- Return
27
- ------
28
- func:
29
- Function that will load defaults.
30
-
31
- Notes
32
- -----
33
- This decorator will override any default values set in the function definition.
34
- """
35
- def decorator(func):
36
- @functools.wraps(func)
37
- def wrapper(*args, **kwargs):
38
- for key, val in defaults.items():
39
- if kwargs.get(key) is None:
40
- kwargs[key] = val
41
- return func(*args, **kwargs)
42
- return wrapper
43
- return decorator
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes