Spello Consulting Foundation Library
Available Classes
The Spello Consulting Foundation library provides some foundational classes for:
- SCCommon: Some common functions used by other classes.
- SCConfigManager: Reading from and validating YAML style config files
- SCLogging: Logging messages to the console and a log file and sending email in plain text or HTML format
- CSVReader: Reading data from and and writing to CSV files
- DateHelper: Date and datetime helper functions
- JSONEncoder: Helps convert dicts and lists to json and back, preserving datetime and enum data types.
Installing the library
The library is available from PyPi, so to add it to your Python project use pip:
pip install sc-foundation-services
Or better yet, use UV:
uv add sc-foundation-services
Configuration File
The library uses a YAML file for configuration. An example config file (config.yaml.example) is available on Github. Copy this to [your_app_name].yaml before using the library.
Here's the example file - the library expects to find the Files and Email sections in the file:
AmberAPI:
APIKey: somerandomkey342
BaseUrl: https://api.amber.com.au/v1
Timeout: 15
Files:
LogfileName: logfile.log
LogfileMaxLines: 500
LogProcessID: False
LogfileVerbosity: detailed
ConsoleVerbosity: detailed
Email:
EnableEmail: True
SMTPServer: smtp.gmail.com
SMTPPort: 587
SMTPUsername: me@gmail.com
SMTPPassword: <Your SMTP password>
SubjectPrefix: "[Bob Portfolio]: "
Configuration Parameters
Section: Files
| Parameter | Description |
|---|---|
| LogfileName | The name of the log file, can be a relative or absolute path. |
| LogfileMaxLines | Maximum number of lines to keep in the log file. If zero, file will never be truncated. |
| LogfileVerbosity | The level of detail captured in the log file. One of: none; error; warning; summary; detailed; debug; all |
| ConsoleVerbosity | Controls the amount of information written to the console. One of: error; warning; summary; detailed; debug; all. Errors are written to stderr all other messages are written to stdout |
Section: Email
| Parameter | Description |
|---|---|
| EnableEmail | Set to True if you want to allow the app to send emails. If True, the remaining settings in this section must be configured correctly. |
| SMTPServer | The SMTP host name that supports TLS encryption. If using a Google account, set to smtp.gmail.com |
| SMTPPort | The port number to use to connect to the SMTP server. If using a Google account, set to 587 |
| SMTPUsername | Your username used to login to the SMTP server. If using a Google account, set to your Google email address. Alternatively, set the SMTP_USERNAME environment variable. |
| SMTPPassword | The password used to login to the SMTP server. If using a Google account, create an app password for the app at https://myaccount.google.com/apppasswords. Alternatively, set the SMTP_PASSWORD environment variable. |
| SubjectPrefix | Optional. If set, the app will add this text to the start of any email subject line for emails it sends. |
Example code
Here's an example module that shows how to use the library classes. Use the API Reference navigation to view the API methods for each class. The code example and the companion config and Excel files is available in the examples/ folder in the Github repo.
# ruff: noqa: INP001
"""Example code using the sc-foundation libraries."""
import datetime as dt
import platform
import sys
from example_config_schemas import ConfigSchema
from sc_foundation import CSVReader, DateHelper, SCConfigManager, SCLogger
CONFIG_FILE = "examples/example_config.yaml"
CSV_FILE = "examples/example_csv.csv"
def update_csv():
header_config = [
{
"name": "Symbol",
"type": "str",
"match": True,
"sort": 2,
},
{
"name": "Date",
"type": "date",
"format": "%Y-%m-%d",
"match": True,
"sort": 1,
"minimum": None,
},
{
"name": "Name",
"type": "str",
},
{
"name": "Currency",
"type": "str",
},
{
"name": "Price",
"type": "float",
"format": ".2f",
},
]
extra_data = [
{
"Symbol": "AAPL",
"Date": dt.date(2023, 10, 1),
"Name": "Apple Inc.",
"Currency": "USD",
"Price": 150.00,
},
]
# Create an instance of the CSVReader class
try:
csv_reader = CSVReader(CSV_FILE, header_config)
except (ImportError, TypeError, ValueError) as e:
print(e, file=sys.stderr)
return
csv_reader.update_csv_file(extra_data)
def main():
"""Main function to run the example code."""
print(f"Hello from sc-foundation running on {platform.system()}")
# Get our default schema, validation schema, and placeholders
schemas = ConfigSchema()
# Initialize the SC_ConfigManager class
try:
config = SCConfigManager(
config_file=CONFIG_FILE,
default_config=schemas.default,
validation_schema=schemas.validation,
placeholders=schemas.placeholders
)
except RuntimeError as e:
print(f"Configuration file error: {e}", file=sys.stderr)
return
# Print a value from the sample config file
print(f"API key = {config.get('AmberAPI', 'APIKey')}")
# Initialize the SC_Logger class
try:
logger = SCLogger(config.get_logger_settings())
except RuntimeError as e:
print(f"Logger initialisation error: {e}", file=sys.stderr)
return
logger.log_message("This is a test message at the summary level.", "summary")
# Setup email
email_settings = config.get_email_settings()
if email_settings is not None:
logger.register_email_settings(email_settings)
text_msg = "Hello world from sc-foundation example code."
if logger.send_email("Hello world", text_msg):
logger.log_message("Email sent OK.", "detailed")
# Use DateHelper to get the current date and time
prior_date = DateHelper.today_add_days(-7)
print(f"Prior date (7 days ago): {prior_date}")
# Update a CSV file
update_csv()
# See if we have a fatal error from a previous run
if logger.get_fatal_error():
print("Prior fatal error detected.")
logger.clear_fatal_error()
if __name__ == "__main__":
main()