Skip to main content

humon

A Python wrapper for the Humon C API. This project uses Cython, so can theoretically be used wherever Cython modules can be used.

Installation

Thus far, the Python wrapper has only been tested on Linux-like systems. Available as a PyPI package:

$ pip install humon

Or, you can clone it from github:

$ git clone https://github.com/spacemeat/humon-cy
$ pip install ./humon-cy

It's best practice to emplace it in a virtual environment.

API overview

See the Humon project readme for comprehensive details about Humon's format. This readme only describes the Python interface. The API is not strictly 1-1 with the C/C++ APIs.

Loading troves

Easy. There are two ways:

import humon as h
eqipment_trove = h.from_file('equipment.hu') # default encoding = h.Encoding.UNKNOWN
quests_trove = h.from_file('equipment.hu', h.Encoding.UTF8)
import humon as h
trove = h.from_string('{foo: bar}')

The file on disk may be encoded with any UTF-n format, as in the C API. Python strings are already Unicode-encoded, and will be converted to UTF-8 (Humon's internal format) if need be.

The returned trove is the container for the Humon data. It will hold the entire file or string, and provide very quick access to the contents for reading once loaded. Troves are immutable once created.

Both functions also take an optional parameter tab_size: int. This is to help error diagnostics determine the correct column.

Accessing nodes

For much of the rest of this document, we'll utilize a sample Humon file on disk:

$ cat gnome.hu
@ { app: gamin'-djinn, component: assets-gnome, version: 0.1.0 }
{
    model: gnome-generic.fbx
    textures: [
        gnome-generic-albedo.png
        gnome-generic-bump.png          @ units: model-space
        gnome-generic-metallic.png
    ]
    animations: {
        idle: [
            gnome-idle_0.anim
            gnome-idle_1.anim
        ]
    }
}

Humon data is a tree of nodes: lists, dicts, and values, organized like JSON data. There are also comments and annotations, and all of this is described in the Humon project readme. Currently, comments cannot be accessed through the API, though that is forthcoming.

Getting the root node is done through the root property of a trove:

import humon as h
trove = h.from_string('{foo: [a b c d]}')
root = trove.root

The returned object is of type Node. You can access its kind--list, dict, value--by the kind property. A list or dict will have child nodes, accessible through getitem(). Any child of a dict will have a key property. A value node will have a value property.

import humon as h
trove = h.from_string('{foo: [a b c d]}')
root = trove.root
assert root.kind == NodeKind.DICT
lnode = root['foo']
vnode = lnode[2]
print (vnode.value)  # prints: c

A minor difference between Humon and JSON is that Humon dict entries can be accessed by index as well, and keep their order as loaded. (This is a strict language feature, and not dependent on any API.)

import humon as h
trove = h.from_string('{foo: foofoo, bar: barbar, baz: bazbaz}')
vnode = trove.root[2]
print (vnode.value)  # prints bazbaz

Another minor difference between Humon and JSON is that Humon dicts do not have to have unique keys. You can access the nth child node with a given key:

import humon as h
trove = h.from_string('''{ foo: [a b c d]
                                 bar: snaa
                                 foo: [e f g h]
                                 baz: plugh
                                 foo: [i j k l] }''')
vnode = trove.root['foo', 2]
print (f'{vnode.address}: {vnode.value}') # prints: /foo: [i j k l]

You can also access nodes via address:

import humon as h
trove = h.from_string('{foo: [a b c d]}')
vnode = trove.get_node('/foo/2')
print (f'{vnode.address}: {vnode.value}') # prints: /foo/2: c
vnode = vnode.get_node('../3')
print (f'{vnode.address}: {vnode.value}') # prints: /foo/3: d

Nodes which share a parent are sibling nodes:

import humon as h
trove = h.from_string('{foo: [a b c d] bar: [e f g h]}')
vnode = trove.get_node('/foo')
print (f'{vnode.address}: {vnode.value}') # prints: /foo: [a b c d]
vnode = vnode.get_sibling('bar')
print (f'{vnode.address}: {vnode.value}') # prints: /bar: [e f g h]
vnode = vnode[0].sibling()
print (f'{vnode.address}: {vnode.value}') # prints: /bar/0: e

A trove stores nodes as a linear array internally, and nodes can be accessed by index from the Trove ojbect:

import humon as h
trove = h.from_string('{foo: [a b c d]}')
print (trove.get_node(4).value) # prints: c

Annotations

Annotations on a trove or node are returned as dicts. Assuming a reasonable implementation of a Version class:

import humon as h

data = '''@ { app: gamin'-djinn, component: assets-gnome, version: 0.1.0 }
{
    model: gnome-generic.fbx
    textures: [
        gnome-generic-albedo.png
        gnome-generic-bump.png          @ units: model-space
        gnome-generic-metallic.png
    ]
    animations: {
        idle: [
            gnome-idle_0.anim
            gnome-idle_1.anim
        ]
    }
}'''

trove = h.from_string(data)
to = trove.annotations
assert to['app'] == "gamin'-djinn"
if Version(to['version']).in_range('0.0.4', '0.1.3'):
    print (trove.get_node('/textures/1').annotations) # prints: {'units': 'model-space'}

Serializing

Though a trove is immutable, it can be printed in a few ways. The most useful maybe is with Trove.to_string() and Trove.to_file():

...
s = trove.to_string(h.WhitespaceFormat.MINIMAL, print_comments = False)

The minimal formatting reduces the whitespace to a minimum while keeping Humon semantics the same. You can do a pretty formatting as well:

...
trove.to_file(path: 'pretty.h',
              whitespace_format = h.WhitespaceFormat.PRETTY, indent_size = 4,
              indent_with_tabs = False, use_colors = True, color_table = None, 
              print_comments = True, newline = '\n', print_bom = True)

Passing True to use_colors will insert colorizing markup entries appropriately in the resutlant string. If you specify use_colors, but do not provide a color table, the API will use some ANSI color codes as default values. Set color entries for each color type like so:

...
named_fg = {
    'black': '\033[30m',
    'red': '\033[31m',
    'green': '\033[32m',
    'yellow': '\033[33m',
    'blue': '\033[34m',
    'magenta': '\033[35m',
    'cyan': '\033[36m',
    'white': '\033[37m',

    'bright black': '\033[90m',
    'bright red': '\033[91m',
    'bright green': '\033[92m',
    'bright yellow': '\033[93m',
    'bright blue': '\033[94m',
    'bright magenta': '\033[95m',
    'bright cyan': '\033[96m',
    'bright white': '\033[97m',
}

color_table = {
    h.ColorCode.TOKENSTREAMBEGIN: '',
    h.ColorCode.TOKENSTREAMEND: '\033[0m',
    h.ColorCode.TOKENEND: '',
    h.ColorCode.PUNCLIST: named_fg['bright white'],
    h.ColorCode.PUNCDICT: named_fg['bright white'],
    h.ColorCode.PUNCKEYVALUESEP: named_fg['bright white'],
    h.ColorCode.PUNCANNOTATE: named_fg['bright blue'],
    h.ColorCode.PUNCANNOTATEDICT: named_fg['bright blue'],
    h.ColorCode.PUNCANNOTATEKEYVALUESEP: named_fg['blue'],
    h.ColorCode.KEY: named_fg['cyan'],
    h.ColorCode.VALUE: named_fg['bright cyan'],
    h.ColorCode.COMMENT: named_fg['red'],
    h.ColorCode.ANNOKEY: named_fg['magenta'],
    h.ColorCode.ANNOVALUE: named_fg['bright magenta'],
    h.ColorCode.WHITESPACE: named_fg['white'],
}

trove.to_file(path: 'pretty.h',
              whitespace_format = h.WhitespaceFormat.PRETTY, indent_size = 4,
              indent_with_tabs = False, use_colors = True, color_table = color_table,
              print_comments = True, newline = '\n', print_bom = True)

You can also access full text in a node or trove with token_string:

import humon as h
trove = h.from_string('{foo: [a b {color: {green: [froggy, leafy]}} d]}')
print (trove.get_node('/foo/2').token_string)   # prints: {green: [froggy, leafy]}}
print (trove.token_string)                      # prints the whole trove

Calling token_string on the trove is nearly equivalent to calling 'Trove.to_string' with whitespace_format set to humon.WhitespaceFormat.CLONED and no colors. But, since it copies directly from the loaded text, it is much faster.

Metadata

Release files for humon 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for humon 0.1.0
File Size Uploaded
humon-0.1.0.tar.gz 181.5 kB Details

Release files / humon-0.1.0.tar.gz

Download URL humon-0.1.0.tar.gz
Size 181.5 kB
Tags Source
SHA-256 checksum
How to use checksums
48db90b0031f395ad84280df45ba403bb6f21e969c5b4d7b7c1fa0efdbfe37eb
BLAKE2b-256 checksum
How to use checksums
86bf155ca0a354b2c216fdf60ade895437d8428a88d9268cacd9754ba1b997d9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/5.1.0 CPython/3.10.12

Release history Release notifications | RSS feed

This release

0.1.0 This release

1 release file

0.0.4

1 release file

0.0.3

1 release file

0.0.1

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page