varfile 0.1.0__py3-none-any.whl

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.
varfile/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ from .parser import load, loads, dump, dumps, VarConfig
2
+
3
+ __all__ = ['load', 'loads', 'dump', 'dumps', 'VarConfig']
varfile/parser.py ADDED
@@ -0,0 +1,140 @@
1
+ import os
2
+
3
+ class VarConfig(dict):
4
+ """A dictionary subclass that allows dot-notation access (e.g., config.Database.host)."""
5
+ def __init__(self, *args, **kwargs):
6
+ super().__init__(*args, **kwargs)
7
+ # Recursively convert nested dictionaries into VarConfig objects
8
+ for k, v in self.items():
9
+ if isinstance(v, dict) and not isinstance(v, VarConfig):
10
+ self[k] = VarConfig(v)
11
+
12
+ def __getattr__(self, key):
13
+ try:
14
+ return self[key]
15
+ except KeyError:
16
+ raise AttributeError(f"'VarConfig' object has no attribute '{key}'")
17
+
18
+ def __setattr__(self, key, value):
19
+ if isinstance(value, dict) and not isinstance(value, VarConfig):
20
+ value = VarConfig(value)
21
+ self[key] = value
22
+
23
+
24
+ def _strip_comment(line: str) -> str:
25
+ """Strips trailing comments while ignoring '#' characters inside quotes."""
26
+ in_quote = False
27
+ quote_char = None
28
+
29
+ for i, char in enumerate(line):
30
+ if char in ('"', "'"):
31
+ if not in_quote:
32
+ in_quote = True
33
+ quote_char = char
34
+ elif char == quote_char:
35
+ in_quote = False
36
+ quote_char = None
37
+ elif char == '#' and not in_quote:
38
+ return line[:i] # Return everything before the comment
39
+ return line
40
+
41
+
42
+ def _parse_value(val: str):
43
+ """Converts text values into native Python types."""
44
+ val = val.strip()
45
+
46
+ # Handle Strings
47
+ if (val.startswith('"') and val.endswith('"')) or (val.startswith("'") and val.endswith("'")):
48
+ return val[1:-1]
49
+
50
+ # Handle Booleans
51
+ if val.lower() == 'true':
52
+ return True
53
+ if val.lower() == 'false':
54
+ return False
55
+
56
+ # Handle Numbers
57
+ try:
58
+ if '.' in val:
59
+ return float(val)
60
+ return int(val)
61
+ except ValueError:
62
+ pass
63
+
64
+ return val
65
+
66
+
67
+ def _format_value(val) -> str:
68
+ """Formats a Python type back into a .var valid string syntax."""
69
+ if isinstance(val, bool):
70
+ return "true" if val else "false"
71
+ if isinstance(val, str):
72
+ return f'"{val}"'
73
+ return str(val)
74
+
75
+
76
+ # --- READ FUNCTIONS ---
77
+
78
+ def loads(content: str) -> VarConfig:
79
+ """Parses a string of .var data into a VarConfig object."""
80
+ data = {}
81
+ current_context = data
82
+
83
+ for line in content.splitlines():
84
+ line = _strip_comment(line).strip()
85
+ if not line:
86
+ continue
87
+
88
+ # Handle Classes / Sections
89
+ if line.startswith('[') and line.endswith(']'):
90
+ class_name = line[1:-1].strip()
91
+ data[class_name] = {}
92
+ current_context = data[class_name]
93
+ continue
94
+
95
+ # Handle Key = Value
96
+ if '=' in line:
97
+ key, val = line.split('=', 1)
98
+ current_context[key.strip()] = _parse_value(val)
99
+
100
+ return VarConfig(data)
101
+
102
+
103
+ def load(filepath: str) -> VarConfig:
104
+ """Reads a .var file and parses it into a VarConfig object."""
105
+ if not os.path.exists(filepath):
106
+ raise FileNotFoundError(f"The file {filepath} does not exist.")
107
+
108
+ with open(filepath, 'r', encoding='utf-8') as f:
109
+ return loads(f.read())
110
+
111
+
112
+ # --- WRITE FUNCTIONS ---
113
+
114
+ def dumps(data: dict) -> str:
115
+ """Serializes a dictionary/VarConfig back into a .var string format."""
116
+ lines = []
117
+ sections = {}
118
+
119
+ # Separate top-level variables and sub-classes
120
+ for k, v in data.items():
121
+ if isinstance(v, dict):
122
+ sections[k] = v
123
+ else:
124
+ lines.append(f"{k} = {_format_value(v)}")
125
+
126
+ # Format sub-classes
127
+ for section_name, section_data in sections.items():
128
+ if lines: # Add an empty line separation between sections
129
+ lines.append("")
130
+ lines.append(f"[{section_name}]")
131
+ for k, v in section_data.items():
132
+ lines.append(f"{k} = {_format_value(v)}")
133
+
134
+ return "\n".join(lines)
135
+
136
+
137
+ def dump(data: dict, filepath: str):
138
+ """Writes a dictionary/VarConfig into a physical .var file."""
139
+ with open(filepath, 'w', encoding='utf-8') as f:
140
+ f.write(dumps(data))
@@ -0,0 +1,177 @@
1
+ Metadata-Version: 2.4
2
+ Name: varfile
3
+ Version: 0.1.0
4
+ Summary: A simple parser for .var variable files with object-mapping support
5
+ Author: Ely
6
+ Requires-Python: >=3.8
7
+ Description-Content-Type: text/markdown
8
+
9
+ # varfile
10
+
11
+ **varfile** is a fast, lightweight, zero-dependency Python library for working with `.var` configuration files. It combines the simplicity of INI-style configs with Python-friendly object access, automatic type conversion, and easy file editing.
12
+
13
+ ## Features
14
+
15
+ * **Dot Notation Access**
16
+ Access configuration values naturally:
17
+
18
+ ```python
19
+ config.Database.host
20
+ ```
21
+
22
+ instead of:
23
+
24
+ ```python
25
+ config["Database"]["host"]
26
+ ```
27
+
28
+ * **Automatic Type Conversion**
29
+ Values are automatically converted to the appropriate Python types:
30
+
31
+ * `int`
32
+ * `float`
33
+ * `bool`
34
+ * `str`
35
+
36
+ * **Easy Editing**
37
+ Modify values directly in memory and save them back to disk with a single command.
38
+
39
+ * **Robust Parsing**
40
+ Handles comments, special characters, URLs containing `#`, and other common edge cases.
41
+
42
+ * **Clean Serialization**
43
+ Preserves formatting conventions such as lowercase booleans (`true` / `false`) when writing files.
44
+
45
+ ---
46
+
47
+ # Installation
48
+
49
+ Install with pip:
50
+
51
+ ```bash
52
+ pip install varfile
53
+ ```
54
+
55
+ Or with uv:
56
+
57
+ ```bash
58
+ uv add varfile
59
+ ```
60
+
61
+ ---
62
+
63
+ # Quick Start
64
+
65
+ ## 1. Create a `.var` File
66
+
67
+ Create a file named `demo.var`:
68
+
69
+ ```ini
70
+ # Global settings
71
+ app_name = "Varfile Demo"
72
+ environment = "development"
73
+ debug_mode = true
74
+ max_users = 150
75
+
76
+ [Database]
77
+ host = "127.0.0.1"
78
+ port = 5432
79
+ timeout = 45.8
80
+ enabled = false
81
+ url = "https://varfiletest.com/#user1"
82
+ ```
83
+
84
+ ---
85
+
86
+ ## 2. Read Configuration Values
87
+
88
+ Load a file and access values using dot notation:
89
+
90
+ ```python
91
+ import varfile
92
+
93
+ config = varfile.load("demo.var")
94
+
95
+ print(config.app_name) # Varfile Demo
96
+ print(config.max_users) # 150
97
+ print(config.Database.port) # 5432
98
+ print(config.Database.enabled) # False
99
+ ```
100
+
101
+ ---
102
+
103
+ ## 3. Modify and Save Values
104
+
105
+ Update values in memory and write them back to the file:
106
+
107
+ ```python
108
+ import varfile
109
+
110
+ config = varfile.load("demo.var")
111
+
112
+ config.max_users = 100
113
+ config.Database.port = 5000
114
+
115
+ varfile.dump(config, "demo.var")
116
+
117
+ print("Configuration updated successfully!")
118
+ ```
119
+
120
+ ---
121
+
122
+ ## 4. Create a Configuration From Scratch
123
+
124
+ You can also build configuration files programmatically:
125
+
126
+ ```python
127
+ import varfile
128
+
129
+ config = varfile.VarConfig()
130
+
131
+ config.new_setting = "Hello World"
132
+ config.user_count = 1
133
+
134
+ config.FeatureToggle = {
135
+ "dark_mode": True,
136
+ "beta_tester": False
137
+ }
138
+
139
+ varfile.dump(config, "new_config.var")
140
+ ```
141
+
142
+ Generated `new_config.var`:
143
+
144
+ ```ini
145
+ new_setting = "Hello World"
146
+ user_count = 1
147
+
148
+ [FeatureToggle]
149
+ dark_mode = true
150
+ beta_tester = false
151
+ ```
152
+
153
+ ---
154
+
155
+ # API Reference
156
+
157
+ | Function / Class | Description |
158
+ | -------------------------------- | --------------------------------------------------------------------- |
159
+ | `varfile.load(filepath)` | Load a `.var` file from disk and return a `VarConfig` object. |
160
+ | `varfile.dump(config, filepath)` | Save a `VarConfig` object to a `.var` file. |
161
+ | `varfile.loads(string_data)` | Parse `.var` content from a string. |
162
+ | `varfile.dumps(config)` | Convert a configuration object into `.var` formatted text. |
163
+ | `varfile.VarConfig()` | Create a new empty configuration container with dot notation support. |
164
+
165
+ ---
166
+
167
+ # Why varfile?
168
+
169
+ Many configuration formats are either too limited or unnecessarily complex. varfile aims to provide a middle ground:
170
+
171
+ * Easy to read
172
+ * Easy to edit
173
+ * Python-friendly
174
+ * No external dependencies
175
+ * Clean object-style access
176
+
177
+ Whether you're building a small script or a larger application, varfile keeps configuration management simple.
@@ -0,0 +1,6 @@
1
+ varfile/__init__.py,sha256=8Q-aFP_qCzNTSRJ4X9MmyXna0L65slAhAwzfunAdGbs,116
2
+ varfile/parser.py,sha256=ylNHD7DR20xVB9e9uIfABoidFaOATdjZEJIwpZ3n7dk,4296
3
+ varfile-0.1.0.dist-info/METADATA,sha256=-tkQEUfNZHh2E6eu2k4EIinoQa0da9OaiKO1GsJwTvY,3970
4
+ varfile-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
5
+ varfile-0.1.0.dist-info/top_level.txt,sha256=R1gipGfCDtqh9SPJOllm4PJb5BGcrWONpLLndHONxUs,8
6
+ varfile-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ varfile