structcfg-parser
Python parser for SCL (Structured Configuration Language) — a simple, human-readable configuration format with explicit typing.
pip install structcfg-parser
Quick Start
import scl_parser
config = scl_parser.loads("""
app :: class {
name :: str { My Application }
port :: num { 8080 }
debug :: bool { true }
}
""")
print(config["app"]["name"]) # My Application
print(config["app"]["port"]) # 8080
API
Parsing
loads(text: str) -> dict
Parse SCL string to dict. Comments are not preserved.
config = scl_parser.loads("count :: num { 42 }")
print(config["count"]) # 42
load(filename: str, encoding: str = "utf-8") -> dict
Load and parse SCL file to dict.
config = scl_parser.load("config.scl")
loadsWithComments(text: str) -> SCLDocument
Parse SCL string to SCLDocument, preserving comments.
doc = scl_parser.loadsWithComments("""
[ database settings ]
host :: str { localhost } [ can be overridden via env ]
""")
print(doc["host"]) # localhost
print(doc.getComment("host")) # database settings
print(doc.getInlineComment("host")) # can be overridden via env
loadWithComments(filename: str, encoding: str = "utf-8") -> SCLDocument
Load SCL file to SCLDocument.
doc = scl_parser.loadWithComments("config.scl")
Serialization
dumps(data: dict | SCLDocument, indent: int = 4) -> str
Serialize dict or SCLDocument to SCL string.
config = {"host": "localhost", "port": 5432}
print(scl_parser.dumps(config))
# host :: str { "localhost" }
# port :: num { 5432 }
dump(data: dict | SCLDocument, filename: str, indent: int = 4, encoding: str = "utf-8")
Save dict or SCLDocument to file.
scl_parser.dump(config, "output.scl")
dumpsWithComments(doc: SCLDocument, indent: int = 4) -> str
Serialize SCLDocument to SCL string with comments. Requires SCLDocument — use dumps() for plain dict.
dumpWithComments(doc: SCLDocument, filename: str, indent: int = 4, encoding: str = "utf-8")
Save SCLDocument to file with comments. Requires SCLDocument.
SCLDocument
SCLDocument is returned by loadsWithComments / loadWithComments. It provides dict-like access to values and full control over comments.
doc = scl_parser.loadsWithComments(text)
# dict-like access
doc["key"]
doc["key"] = value
del doc["key"]
"key" in doc
len(doc)
# explicit methods
doc.get("key", default=None)
doc.set("key", value, comment="...", inlineComment="...")
doc.delete("key")
doc.has("key")
doc.keys()
doc.values()
doc.items()
# comments
doc.getComment("key") # comment before parameter
doc.getInlineComment("key") # comment on the same line
doc.setComment("key", "...")
doc.setInlineComment("key", "...")
doc.getHeaderComment() # comment at top of file
doc.setHeaderComment("...")
# conversion
doc.toDict() # plain dict, comments lost
SCLDocument.fromDict(d) # create from dict, no comments
Building a document from scratch:
doc = scl_parser.SCLDocument()
doc.setHeaderComment("generated config")
doc.set("host", "localhost", comment="database host")
doc.set("port", 5432, inlineComment="default postgres port")
print(scl_parser.dumpsWithComments(doc))
# [ generated config ]
#
# [ database host ]
# host :: str { "localhost" }
# port :: num { 5432 } [ default postgres port ]
Error Handling
try:
config = scl_parser.load("config.scl")
except FileNotFoundError:
print("file not found")
except scl_parser.SCLSyntaxError as e:
print(f"syntax error: {e}")
except scl_parser.SCLParseError as e:
print(f"parse error: {e}")
Language Reference
Syntax
name :: type { value }
Comments use square brackets:
[ this is a comment ]
name :: str { hello } [ inline comment ]
Types
| Type | Description | Example |
|---|---|---|
bool |
Boolean | enabled :: bool { true } |
str |
String | name :: str { hello } |
num |
Integer | count :: num { 42 } |
fl |
Float | price :: fl { 19.99 } |
ml |
Multiline string | text :: ml { 'line1\nline2' } |
class |
Object (key-value pairs) | user :: class { ... } |
list(T) / list[T] |
Typed list | items :: list[num] { 1, 2, 3 } |
dynamic |
Any scalar value | value :: dynamic { 42 } |
bool
enabled :: bool { true }
flag :: bool { false }
active :: bool { yes } [ yes/no are valid aliases ]
inactive :: bool { no }
str
Values can be written with or without quotes. Quoted strings support escape sequences.
[ unquoted — literal text until } ]
greeting :: str { hello world }
[ quoted ]
path :: str { "C:\\Users\\admin" }
message :: str { "say \"hi\"" }
newline :: str { "line1\nline2" }
tab :: str { "col1\tcol2" }
unicode :: str { "\u041F\u0440\u0438\u0432\u0435\u0442" }
Supported escapes: \\, \", \', \n, \t, \uXXXX, any other \x → x.
num / fl
count :: num { 42 }
negative :: num { -10 }
price :: fl { 19.99 }
ratio :: fl { 0.5 }
ml
Multiline string. Value can be quoted with '...' or written plain.
[ quoted — supports escape sequences ]
body :: ml {
'line one\nline two\ttabbed'
}
[ plain — literal text until } ]
note :: ml { some plain text }
class
Nested object with any number of parameters. Nesting is unlimited.
server :: class {
host :: str { localhost }
port :: num { 8080 }
tls :: bool { false }
}
org :: class {
department :: class {
team :: class {
lead :: str { Alice }
}
}
}
list
Strongly typed, homogeneous list. Type is specified in () or [] — both are accepted.
primes :: list(num) { 2, 3, 5, 7 }
tags :: list[str] { "alpha", "beta" }
flags :: list[bool] { true, false, true }
List of objects:
users :: list(class) {
{
name :: str { Alice }
age :: num { 30 }
},
{
name :: str { Bob }
age :: num { 25 }
}
}
Nested lists:
matrix :: list[list[num]] {
{ 1, 2, 3 },
{ 4, 5, 6 }
}
dynamic
Any scalar value — type is inferred at runtime.
setting :: dynamic { 42 }
flag :: dynamic { true }
label :: dynamic { "hello" }
ratio :: dynamic { 3.14 }
mixed :: list(dynamic) { 1, "text", true, 3.14 }
Links
- SCL Specification: github.com/shareui/scl
- Issues: github.com/shareui/scl/issues
- Author: shareui
Metadata
Release files for structcfg-parser 1.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| structcfg_parser-1.2.0.tar.gz | 14.1 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| structcfg_parser-1.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 28.8 kB
Release files / structcfg_parser-1.2.0.tar.gz
| Download URL | structcfg_parser-1.2.0.tar.gz |
|---|---|
| Size | 14.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
461de014b5bd0746617a32a982d5ea4f81e8d233ae4a43679ea17be03402debe
|
|
BLAKE2b-256 checksum How to use checksums |
0cfdb1cb3480344cc584b0d0ac6860e2c37c70da055456750d761f5dbb34dbe9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.12
|
Release files / structcfg_parser-1.2.0-py3-none-any.whl
| Download URL | structcfg_parser-1.2.0-py3-none-any.whl |
|---|---|
| Size | 14.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b0e29f06fab8a5416c9fabe82b8f0992d1ece08d34307af5e094ba2af57736ad
|
|
BLAKE2b-256 checksum How to use checksums |
5bf9e679cd4ee447c5a8878bb6e1f0f542cfb0061c9573d938d0348e8aa01ab3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.12
|
Security for structcfg-parser 1.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.