Python configuration dialog
satya - 2/25/2024, 2:04:27 PM
toml install
pip install tomlkit
satya - 2/25/2024, 2:04:52 PM
toml to json
import tomlkit
import json
# Function to convert TOML file to JSON file
def toml_to_json(toml_file_path, json_file_path):
# Read TOML file
with open(toml_file_path, 'r') as toml_file:
toml_data = toml_file.read()
# Parse TOML data
parsed_toml = tomlkit.parse(toml_data)
# Convert parsed TOML to JSON string
json_data = json.dumps(parsed_toml, indent=4)
# Write JSON data to file
with open(json_file_path, 'w') as json_file:
json_file.write(json_data)
# Example usage
toml_to_json('example.toml', 'example.json')
satya - 2/25/2024, 2:07:36 PM
Dictonary to toml
import toml
# Example Python object
data = {
"database": {
"server": "192.168.1.1",
"ports": [8001, 8002, 8003],
"connection_max": 5000,
"enabled": True
},
"servers": {
"alpha": {"ip": "10.0.0.1", "dc": "eqdc10"},
"beta": {"ip": "10.0.0.2", "dc": "eqdc10"}
}
}
# Convert Python object to TOML string
toml_string = toml.dumps(data)
# Write TOML string to file
with open('example.toml', 'w') as toml_file:
toml_file.write(toml_string)
satya - 2/25/2024, 2:13:41 PM
json string to a dict object
json_string = '{"name": "John Doe", "age": 30, "is_student": false}'
# Convert JSON string to Python dictionary
data_dict = json.loads(json_string)
print(data_dict)
satya - 2/25/2024, 2:20:07 PM
Example of TOML
# Example TOML configuration
title = "TOML Example"
[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00Z # First-class support for dates and times
[database]
server = "192.168.1.1"
ports = [ 8001, 8001, 8002 ]
connection_max = 5000
enabled = true
[servers]
# Indentation is optional but can improve readability
[servers.alpha]
ip = "10.0.0.1"
dc = "eqdc10"
[servers.beta]
ip = "10.0.0.2"
dc = "eqdc10"
[[products]] # Array of tables
name = "Hammer"
sku = 738594937
[[products]]
name = "Nail"
sku = 284758393
color = "gray"
satya - 2/25/2024, 2:27:44 PM
JSON to TOML
#Get a dict object first
json_str: str
d: dict = json.loads(json_str)
#Now convert the dict to TOML
toml_str: str = tomlkit.dumps(dict)
satya - 2/25/2024, 3:00:48 PM
Round trip from TOML to an Object
def _readTOMLConfigFile() -> AppConfig:
configfile = _getAppTOMLConfigFilename()
toml_str = fileutils.read_text_file(configfile)
parsed_toml: tomlkit.TOMLDocument = tomlkit.parse(toml_str)
json_str: str = json.dumps(parsed_toml,indent=4)
dict = json.loads(json_str)
obj = AppConfig(**dict)
return obj
satya - 2/25/2024, 3:01:15 PM
The object: AppConfig
class AppConfig (BaseModel):
api_token_name: str = ""
embedding_api: str = ""
llm_api: str =""
satya - 2/25/2024, 3:01:34 PM
Toml file
#
#*************************************************
# Application configuration file
#*************************************************
#
api_token_name = "api-token-name"
embedding_api = "embedding api"
llm_api = "llm api"
satya - 2/25/2024, 3:02:33 PM
Imports
from pydantic import BaseModel
import json
import tomlkit
satya - 2/25/2024, 5:29:48 PM
Putting it all together
"""
*************************************************
* baselib related imports
*************************************************
"""
from baselib import baselog as log
from config.appconfig import AppConfig
from config import appconfig as appconfig
def _getAppConfigObject():
log.info("Reading Application configuration file")
return appconfig.readTOMLConfigFile()
def initAppServices(cls):
log.ph1("Initializing App Services")
cls.class_app_config = _getAppConfigObject()
return cls
@initAppServices
class AppServices:
class_app_config: AppConfig
@staticmethod
def config():
return AppServices.class_app_config
"""
*************************************************
* Testing
*************************************************
"""
def _testConfig1():
token = AppServices.config().api_token_name
log.ph("Token from config", token)
def _testConfig2():
a = AppServices.config().embedding_api
log.ph("embedding api", a)
def test():
_testConfig1()
_testConfig2()
def localTest():
log.ph1("Starting local test")
test()
log.ph1("End local test")
if __name__ == '__main__':
localTest()
satya - 3/6/2024, 10:03:25 AM
Reasonable approach to get a project root
def _getProjectRoot():
baselibPath = Path(baselib.__file__)
parent = baselibPath.parent.parent.resolve()
log.ph("baselib path", baselibPath)
log.ph("root", parent)
return parent
"""
Prints the following:
baselib path
***********************
C:\satya\data\code\LearnPythonRepo\baselib\__init__.py
root
***********************
C:\satya\data\code\LearnPythonRepo
"""
satya - 3/6/2024, 10:25:26 AM
resoleve()
- Makes the path absolute
- Correctly represents the separators
satya - 3/6/2024, 3:10:39 PM
Toml config values are typed
- 1. strings have to be quoted
- 2. Numbers no
- 3. Dates no
- 4. Lists have their own syntax
- 5. Booleans no
satya - 3/6/2024, 3:11:00 PM
Strings
# Examples of string values
single_quoted = 'This is a single-quoted string'
double_quoted = "This is a double-quoted string"
multi_line = """This is a
multi-line string"""
satya - 3/6/2024, 3:13:51 PM
Examples
# Examples of boolean values
is_active = true
has_access = false
# Examples of numeric values
age = 30
pi = 3.1415
# Example of datetime value
created_at = 2021-12-14T12:00:00Z
# Example of an array
items = ["item1", "item2", "item3"]
scores = [97, 85, 92]
# Example of keys with special characters
"content-type" = "application/json"
"multi word key" = "value"
satya - 3/17/2024, 10:25:23 AM
Date and time objects in toml
# Date-only format
date = 2022-01-01
# Full date-time with UTC offset
datetime_with_offset = 2022-01-01T12:00:00+01:00
# Full date-time in UTC (Zulu time)
datetime_utc = 2022-01-01T12:00:00Z
# Local date-time (without timezone information)
local_datetime = 2022-01-01T12:00:00
# Time-only format
time = 12:00:00
satya - 3/17/2024, 10:28:53 AM
The three datetime objects
from datetime import (
date,
datetime,
time
)
satya - 3/17/2024, 10:30:19 AM
Rules
- Date-only strings are converted into Python's datetime.date objects, which contain year, month, and day information.
- Full date-time strings, including those with UTC offset or Zulu time (Z), are converted into datetime.datetime objects. These objects include year, month, day, hour, minute, second, microsecond, and timezone information (if specified).
- Local date-time strings (without timezone information) are also converted into datetime.datetime objects, but without timezone information attached.
- Time-only strings are converted into datetime.time objects, containing hour, minute, second, and microsecond.
satya - 3/17/2024, 10:37:24 AM
Briefly
- Date-only strings: datetime.date (year, month, and day): 2022-01-01
- Full date-time string: datetime.datetime: (utc)2022-01-01T12:00:00Z, 2022-01-01T12:00:00+01:00,
- Local date-time strings: datetime.datetime: 2022-01-01T12:00:00
- Time-only strings: datetime.time: hh:mm:ss:microsecond: 12:34:56.789123
satya - 3/17/2024, 11:20:27 AM
SOF: You may need to deal with this: datetime json issues
satya - 3/17/2024, 11:20:55 AM
TypeError: Object of type Date is not JSON serializable
TypeError: Object of type Date is not JSON serializable
Search for: TypeError: Object of type Date is not JSON serializable
satya - 3/17/2024, 12:16:07 PM
Dealing with datetime snafus
"""
*************************************************
* Datetime json support
*************************************************
"""
from datetime import datetime, date, time
from typing import Any, Dict
class TypedDateTimeEncoder(json.JSONEncoder):
def default(self, o: Any) -> Dict[str, Any]:
if isinstance(o, datetime):
return {"type": "datetime", "value": o.isoformat()}
elif isinstance(o, date):
return {"type": "date", "value": o.isoformat()}
elif isinstance(o, time):
return {"type": "time", "value": o.isoformat()}
return super().default(o)
def typed_datetime_decoder(dct: Dict[str, Any]) -> Any:
if "type" in dct and "value" in dct:
type_info = dct["type"]
value = dct["value"]
if type_info == "datetime":
return datetime.fromisoformat(value)
elif type_info == "date":
return date.fromisoformat(value)
elif type_info == "time":
return time.fromisoformat(value)
return dct # Return the original dictionary if no type info is found
satya - 3/17/2024, 12:16:38 PM
using those
json_str: str = json.dumps(parsed_toml,indent=4, cls=TypedDateTimeEncoder)
dict = json.loads(json_str, object_hook=typed_datetime_decoder)
satya - 3/17/2024, 12:20:29 PM
TOML Lists
# An array of integers
numbers = [
1,
2,
3,
4,
5
]
# An array of strings
fruits = [
"apple",
"banana",
"cherry"
]
# An array of floats
floats = [
1.1,
2.2,
3.3
]
# An array of dates
dates = [
2022-01-01,
2022-01-02,
2022-01-03
]
# A nested array
nested_arrays = [
[1, 2],
[3, 4, 5],
[6]
]
satya - 3/17/2024, 3:33:36 PM
strings spanning multiple lines
multi_line_string = """
This is a multi-line string.
Special characters like \n are escaped.
Leading whitespace on the second and subsequent lines is ignored.
"""
satya - 3/17/2024, 3:35:02 PM
Multiline literal strings
multi_line_literal_string = '''
This is a multi-line literal string.
Escape sequences like \n are not escaped.
Leading whitespace on the second and subsequent lines is preserved.
'''
satya - 3/17/2024, 3:36:07 PM
Key elements
- They start with ''', the single quote characters
- Escape sequences are not escaped
- Leading space are preserved
satya - 3/17/2024, 3:37:40 PM
Keeping white spaces
multi_line_string_with_spaces = """
This is a multi-line string with leading whitespace.\
This line has leading spaces that are preserved because of the backslash.\
This line, too.
"""
satya - 3/17/2024, 3:44:55 PM
details
- use \ at the end of the line to preserve white space
- The first newline after """ or ''' is always ignored