braq


Namebraq JSON
Version 0.0.5 PyPI version JSON
download
home_pagehttps://github.com/pyrustic/braq
SummaryCustomizable data format for config files, AI prompts, and more
upload_time2024-03-13 23:07:49
maintainerPyrustic Evangelist
docs_urlNone
authorPyrustic Evangelist
requires_python>=3.5
licenseMIT
keywords data-format config configuration configfile config-files customizable versatile ai-prompts pyrustic
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![PyPI package version](https://img.shields.io/pypi/v/braq)](https://pypi.org/project/braq)
[![Downloads](https://static.pepy.tech/badge/braq)](https://pepy.tech/project/braq)

<!-- Cover -->
<div align="center">
    <img src="https://raw.githubusercontent.com/pyrustic/misc/master/assets/braq/cover.png" alt="Cover image" width="650">
    <p align="center">
    Braq document with 3 sections
    </p>
</div>

<!-- Intro Text -->
# Braq
<b>Customizable data format for config files, AI prompts, and more</b>

This project is part of the [Pyrustic Open Ecosystem](https://pyrustic.github.io).


## Table of contents
- [Overview](#overview)
- [Data format specification](#data-format-specification)
- [Notable use cases](#notable-use-cases)
    - [Config files](#config-files)
    - [AI prompts](#ai-prompts)
    - [Source code documentation](#source-code-documentation)
- [Classes for interacting with a document](#classes-for-interacting-with-a-document)
    - [Base document class](#base-document-class)
    - [File document class](#file-document-class)
- [Section class](#section-class)
- [Base functions](#base-functions)
    - [Parse a document](#parse-a-document)
    - [Parse a document iteratively](#parse-a-document-iteratively)
    - [Read a file](#read-a-file)
    - [Read a file iteratively](#read-a-file-iteratively)
    - [Render a document](#render-a-document)
    - [Write to file](#write-to-file)
- [Braq schema for data validation](#braq-schema-for-data-validation)
- [Misc functions](#misc-functions)
- [Miscellaneous](#miscellaneous)
- [Testing and contributing](#testing-and-contributing)
- [Installation](#installation)


# Overview
**Braq** (pronounced `/ˈbɹæk/`) is a human-readable customizable data format whose reference parser is an eponymous lightweight [Python](https://www.python.org/) library available on [PyPI](#installation).

## Minimal format specification
A Braq **document** is made up of **sections**, each defined by a **header** surrounded by square brackets (hence the name Braq) and a **body** which is just lines of text.

Since a body is arbitrary text, it is possible to embed a complex [dictionary data structure](https://en.wikipedia.org/wiki/Dictionary_(data_structure)) into a section by encoding it with the human-readable [Paradict](https://github.com/pyrustic/paradict) data format.

Its versatility and minimal format specification make Braq highly customizable and therefore allow it to be used in an eclectic set of use cases such as config files, AI prompts, and code documentation.

## Intuitive programming interface
The Braq parser offers an intuitive programming interface to smoothly interact with a Braq document as well as a transparent integration with [Paradict](https://github.com/pyrustic/paradict) for embedding and loading complex dictionary data structures.

Braq provides functions for parsing documents line by line, creating document models, rendering documents, and performing file I/O operations, among other functionalities. 

At a higher level, the `Document` class leverages the base functions to model documents and allow seamless interaction with them. This class also serves as the parent class for `FileDoc` that focuses specifically on documents with associated disk files.

<p align="right"><a href="#readme">Back to top</a></p>


# Data format specification
Here are the specs and recommended practices for a valid and neat Braq document:

- A Braq document, when not empty, can be divided into sections. 

- A **section** is made up of two parts: a **header** and a **body**. 

- The header is defined on its own line, surrounded by two single [square brackets](https://en.wikipedia.org/wiki/Bracket) (opening and closing brackets respectively). 

- The body is what is between two consecutive headers or between a header and the end of the document.

- A section can be defined multiple times in the same document. In this case, the parser will concatenate its bodies from top to bottom.

- A section with an empty header is called an **unnamed section**. 

- It is recommended to define no more than a single occurrence of a section in a document.

- When a document contains a single unnamed section, it is recommended to place this section at the top of the document.

- When an unnamed document starts a document, it is recommended to omit its header.

- A dictionary data structure encoded with the human-readable [Paradict](https://github.com/pyrustic/paradict) data format can be safely embedded into a section. This section should then be referenced as a **dict section**.

- It is recommended to put 1 empty line as spacing between two consecutive sections.


**Example:**

```
This is the unnamed section
that starts this document.

[section 1]
Lorem ipsum dolor sit amet, 
consectetur adipiscing elit.

[section 2]
# dictionary data structure encoded with Paradict
id = 42
user = "alex" 
books = (dict)
    sci-fi = (list)
        "book 1"
        "book 2"
    thriller = (set)
        "book 3"

[section 1]
it is not recommended to multiply the occurrences
of a section, however the parser will append this 
occurrence of 'section 1' to the previous one.
```


<p align="right"><a href="#readme">Back to top</a></p>

# Notable use cases
This section outlines three notable use cases for **Braq**, namely config files, AI prompts, and code documentation.

## Config files
Being able to embed a dictionary data structure in a section makes Braq de facto suitable for config files.

**Example of a Braq config file:**
```
This is the unnamed section of 'my-config.braq' file.
This section will serve as HELP text.

[user]
id = 42
name = 'alex'

[gui]
theme = 'dark'
window-size = '1024x420'
```

**Example of code snippet to consume the config file:**

```python
from braq import FileDoc

confile = FileDoc("my-config.braq")

# build the 'user' dict section
user = confile.build("user")

# test
assert user == {"id": 42, "name": "alex"}

# retrieve the unnamed section
text = confile.get("")  # notice the empty header str

# retrieve the 'user' dict section as a text
text = confile.get("user")

# embed a 'server' dict section in the config file
server_conf = {"ip-address": "127.0.0.1", "port": 80}
confile.embed("server", server_conf)  # change persisted

# batch edit mode (changes are persisted at the end)
with confile.edit_model():  # by default, autosave==True
    # perform several changes here !
    # ...
    confile.embed("gui", {"background": "red", 
                          "size": 42})
    confile.remove("server")
    # ...
```

> A schema can be passed to a `FileDoc` instance to validate dict sections.

## AI prompts
The capability to seamlessly interweave human-readable structured data with prose within a single document is a fundamental capability that a language designed to interact with AI must possess.

Additionally, the fact that Braq natively supports indentation removes the need for input sanitization, thereby eliminating an entire class of injection attacks.

### Specs
Following are specs for building structured AI prompts with Braq:

- A prompt document must start with the **root instructions** defined inside the top unnamed section.
- The next section that the AI should actively care about, after the top unnamed section, should be explicitly referenced in the root instructions.
- User input must be programmatically embedded as a text value of a dictionary key inside a section that is not the top unnamed section.

That's it ! The specification is deliberately short to avoid unnecessary complexity and also to leave room for creativity.

### Example

```
You are an AI assistant, your name is Jarvis.

You will access the websites defined in the WEB section
to answer the question that will be submitted to you.
The question is stored in the 'input' key of the USER 
dict section.

Be kind and consider the conversation history stored
in the 'data' key of the HISTORY dict section.

[USER]
timestamp = 2024-12-25T16:20:59Z
input = (raw)
    Today, I want you to teach me prompt engineering.
    Please be concise.
    ---

[WEB]
https://github.com
https://www.xanadu.net
https://www.wikipedia.org
https://news.ycombinator.com

[HISTORY]
0 = (dict)
    timestamp = 2024-12-20T13:10:51Z
    input = (raw)
        What is the name of the planet
        closest to the sun ?
        ---
    output = (raw)
        Mercury is the planet closest
        to the sun !
        ---
1 = (dict)
    timestamp = 2024-12-22T14:15:54Z
    input = (raw)
        What is the largest planet in
        the solar system?
        ---
    output = (raw)
        Jupiter is the largest planet
        in the solar system !
        ---
```

## Source code documentation
The flexibility of Braq gives the possibility to define custom data formats for specific use cases. Source code documentation is one of those use cases that need Braq with a custom format on top of it.

This is how Braq can be used to document a function:

```python
def add(a, b):
    """
    This function adds together the values of 
    the provided arguments.
    
    [params]
    - a: first integer
    - b: second integer
    
    [return]
    Returns the sum of `a` and `b`
    """
    return a + b
```

> A tool to consume [docstrings](https://en.wikipedia.org/wiki/Docstring) and output browsable Markdown documents is in development.

<p align="right"><a href="#readme">Back to top</a></p>

# Classes for interacting with a document
The library exposes the `Document` and `FileDoc` classes for interacting with documents. In contrary to the `Document` class, `FileDoc` focuses specifically on documents with associated disk files such as **config files**.

## Base document class
The `Document` class creates an editable model of a Braq document and also offers to validate it with a schema.

**Usage example:**

```python
from braq import Document

INIT_TEXT = """
This document contains
configuration data

[user]
id = 42
name = 'alex'
"""

SCHEMA = {"user": {"id": "int", "name": "str"}}

document = Document(INIT_TEXT, schema=SCHEMA)

# get the body of the unnamed section as a text
text = document.get("")  # empty header string

# build the 'user' dict section
user = document.build("user")
# test
assert user == {"id": 42, "name": "alex"}

# set a section (here, we are editing the unnamed section)
document.set("", "line 1\nline 2")
assert document.get("") == "line 1\nline 2"

# embed a 'server' dict section
server_conf = {"ip-address": "127.0.0.1", "port": 80}
document.embed("server", server_conf)

# list headers
assert document.list_headers() == ("", "user", "server")

# validate specific dict sections
# (no args implies that the entire doc will be the target)
document.validate("user", "server")  # returns a bool
# beware, the 'validate' method may raise an exception
# for good reasons !
```

> There is more to discover about the `Document` class, such as the `clear`, `remove`, and `render` methods, exposed properties, and more.


> Check out the documentation for `braq.Document` [here](https://github.com/pyrustic/braq/blob/master/docs/README.md).


## File document class
The `FileDoc` class is based on the **Document** class and focuses specifically on documents with associated disk files such as **config files**.

> As with the `Document` class, a schema can be passed to a `FileDoc` instance to validate dict sections.

```python
from braq import FileDoc

confile = FileDoc("config-file.braq")

# build the 'user' section
user = confile.build("user")

# test
assert user == {"id": 42, "name": "alex"}

# retrieve the unnamed section as a text
text = confile.get("")  # notice the empty header str

# retrieve the 'user' dict section as a text
text = confile.get("user")

# embed a 'server' dict section
server_conf = {"ip-address": "127.0.0.1", "port": 80}
confile.embed("server", server_conf)  # change persisted

# batch edit mode (changes are persisted at the end)
with confile.edit_model():  # by default, autosave==True
    # perform several changes here !
    # ...
    confile.embed("gui", {"color": "blue"})
```

> There is more to discover about the **FileDoc** class, such as the `load`, `save`, and `save_to` methods, exposed properties, and more.

> Check out the documentation for `braq.FileDoc` [here](https://github.com/pyrustic/braq/blob/master/docs/README.md).

<p align="right"><a href="#readme">Back to top</a></p>

# Section class
The `Section` class is an abstraction representing a Braq section. It exposes the `header` and `body` properties and renders itself when its `__str__` method is called implicitly.

```python
import braq

# create a Section object
header, body = "my header", ("line a", "line b")
section = braq.Section(header, body)

# test the properties
assert section.header == "my header"
assert section.body == "line a\nline b"

# test the rendering
assert str(section) == """\
[my header]
line a
line b"""
```

<p align="right"><a href="#readme">Back to top</a></p>

# Base functions
Base classes such as `Document` and `FileDoc` use several public functions under the hood that can be directly called by the programmer at the right time. These basic functions allow you to parse and render documents as well as read and write file documents.

## Parse a document
The library exposes the `parse` function which takes as input the text stream to be parsed, then returns a **dictionary** whose keys and values are strings representing headers and bodies respectively.

> Sections sharing the same header are concatenated !
> The header of an unnamed section is an empty string.

```python
import braq

text = """\
this is the unnamed section at
the top of this document...

[section 1]
this is section 1"""

d = braq.parse(text)

# check headers
assert tuple(d.keys()) == ("", "section 1")
# check the body of 'section 1'
assert d["section 1"] == "this is section 1"
```

> Check out the documentation for `braq.parse` [here](https://github.com/pyrustic/braq/blob/master/docs/README.md).

## Parse a document iteratively
A document can be parsed line by line as following:

```python
import braq

text = """\
this is the unnamed section

[section 1]
this is section 1"""

for header, body in braq.parse_iter(text):
    if header:
        print("[" + header + "]")
    for line in body:
        print(line)
```

Output:

```text
this is the unnamed section

[section 1]
this is section 1
```


> Check out the documentation for `braq.parse_iter` [here](https://github.com/pyrustic/braq/blob/master/docs/README.md).

## Read a file
The library exposes the `read` function which takes as input the path to a file to parse, then returns a dictionary whose keys and values are strings representing headers and bodies respectively.

> Sections sharing the same header are concatenated !

```python
import braq

path = "/home/alex/braqfile.txt"

r = braq.read(path)
assert tuple(r.keys()) == ("", "section 1")
```

> Check out the documentation for `braq.read` [here](https://github.com/pyrustic/braq/blob/master/docs/README.md).

## Read a file iteratively
A large text file can be parsed line by line as following:

```python
import braq

path = "/home/alex/braqfile.txt"

for header, body in braq.read_iter(path):
    if header:
        print("[" + header + "]")
    for line in body:
        print(line)
```
Output:

```text
this is the unnamed section

[section 1]
this is section 1
```

> Check out the documentation for `braq.read_iter` [here](https://github.com/pyrustic/braq/blob/master/docs/README.md).

## Render a document
Rendering a document involves transforming Python objects representing sections into Braq text which is a string that can be displayed on the screen or stored in a file.

The library exposes the `render` function which accepts as input a sequence of sections (either header-body tuples or `Section` objects) and returns a Braq document.

```python
import braq

# sections
section_1 = braq.Section("section 1", "line a\nline b")
section_2 = "section 2", "line c\nline d"
section_3 = "section 3", ("line e", "line f")

# rendering
r = braq.render(section_1, section_2, section_3)

print(r)
```

Output:

```text
[section 1]
line a
line b

[section 2]
line c
line d

[section 3]
line e
line f
```

> The `render` function also accepts the `spacing` argument which defaults to 1 and represents the number of lines of spacing between two adjacent sections.


> Check out the documentation for `braq.render` [here](https://github.com/pyrustic/braq/blob/master/docs/README.md).

## Write to file
Following is a snippet for writting a Braq document to a file:

```python
import braq

# sections
section_1 = braq.Section("", "welcome")
section_2 = braq.Section("section 2")
section_3 = "section 3", ("line a", "line b")

# path to file
path = "/home/alex/braqfile.txt"
# write to file
r = braq.write(section_1, section_2, section_3, dest=path)
```
The contents of the Braq file:
```text
welcome

[section 2]

[section 3]
line a
line b
```


> Check out the documentation for `braq.write` [here](https://github.com/pyrustic/braq/blob/master/docs/README.md).


<p align="right"><a href="#readme">Back to top</a></p>

# Braq schema for data validation
Dict sections can be validated against a Braq schema. A Braq schema is a Python dictionary object that can be passed to a `Document` or a `FileDoc`. The keys of this dictionary are the headers of dict sections to validate and the values are [Paradict](https://github.com/pyrustic/paradict) schemas.

A Paradict schema is a dictionary containing specs for data validation.

A spec is either simply a string that represents an expected data type, or a `Spec` object that can contain a checking function for complex validation.

Supported spec strings are: `dict`, `list`, `set`, `obj`, `bin`, `bin`, `bool`, `complex`, `date`, `datetime`, `float`, `grid`, `int`, `str`, `time`

**Example:**

```python
from paradict.validator import Spec
from braq import Document

# Braq text with 2 dict sections
TEXT = """
[user]
id = 42
name = 'alex'

[server]
ip-address = "127.0.0.1"
port = 80
"""

# Associated schema
SCHEMA = {"user": {"id": "int",
                   "name": "str"},
          "server": {"ip-address": "str",
                     "port": Spec("int", lambda x: 0 < x < 65535)}}

doc = Document(TEXT, schema=SCHEMA)
assert doc.validate()
# beware, the validate function returns a bool
# but it can also raises an exception when something is wrong 
```


<p align="right"><a href="#readme">Back to top</a></p>

# Misc functions
The `check_header` function accepts a line of text as input and then returns a boolean to indicate whether this line is a header or not.

```python
import braq

line_1 = "[my header]"
line_2 = "[this isn't a header] at all"
assert braq.check_header(line_1) is True
assert braq.check_header(line_2) is False
```

The `get_header` function accepts a line of text as input and returns a string if the line is a header. Otherwise, `None` is returned.

```python
import braq

line_1 = "[my header]"
line_2 = "[this isn't a header] at all"
assert braq.get_header(line_1) == "my header"
assert braq.get_header(line_2) is None
```

> Check out the documentation for `braq.check_header` and `braq.get_header` [here](https://github.com/pyrustic/braq/blob/master/docs/README.md).

<p align="right"><a href="#readme">Back to top</a></p>

# Miscellaneous
Collection of miscellaneous notes.

## Cover image
The beautiful cover image is generated with [Carbon](https://carbon.now.sh/about).

<p align="right"><a href="#readme">Back to top</a></p>

# Testing and contributing
Feel free to **open an issue** to report a bug, suggest some changes, show some useful code snippets, or discuss anything related to this project. You can also directly email [me](https://pyrustic.github.io/#contact).

## Setup your development environment
Following are instructions to setup your development environment

```bash
# create and activate a virtual environment
python -m venv venv
source venv/bin/activate

# clone the project then change into its directory
git clone https://github.com/pyrustic/braq.git
cd braq

# install the package locally (editable mode)
pip install -e .

# run tests
python -m unittest discover -f -s tests -t .

# deactivate the virtual environment
deactivate
```

<p align="right"><a href="#readme">Back to top</a></p>

# Installation
**Braq** is **cross-platform**. It is built on [Ubuntu](https://ubuntu.com/download/desktop) and should work on **Python 3.5** or **newer**.

## Create and activate a virtual environment
```bash
python -m venv venv
source venv/bin/activate
```

## Install for the first time

```bash
pip install braq
```

## Upgrade the package
```bash
pip install braq --upgrade --upgrade-strategy eager
```

## Deactivate the virtual environment
```bash
deactivate
```

<p align="right"><a href="#readme">Back to top</a></p>

# About the author
Hello world, I'm Alex, a tech enthusiast ! Feel free to get in touch with [me](https://pyrustic.github.io/#contact) !

<br>
<br>
<br>

[Back to top](#readme)



            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/pyrustic/braq",
    "name": "braq",
    "maintainer": "Pyrustic Evangelist",
    "docs_url": null,
    "requires_python": ">=3.5",
    "maintainer_email": "rusticalex@yahoo.com",
    "keywords": "data-format,config,configuration,configfile,config-files,customizable,versatile,ai-prompts,pyrustic",
    "author": "Pyrustic Evangelist",
    "author_email": "rusticalex@yahoo.com",
    "download_url": "https://files.pythonhosted.org/packages/f2/48/08d05c66ea3e3dc97d8870be862456fa46a0950082e2dd7e046b9e9d63ad/braq-0.0.5.tar.gz",
    "platform": null,
    "description": "[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![PyPI package version](https://img.shields.io/pypi/v/braq)](https://pypi.org/project/braq)\n[![Downloads](https://static.pepy.tech/badge/braq)](https://pepy.tech/project/braq)\n\n<!-- Cover -->\n<div align=\"center\">\n    <img src=\"https://raw.githubusercontent.com/pyrustic/misc/master/assets/braq/cover.png\" alt=\"Cover image\" width=\"650\">\n    <p align=\"center\">\n    Braq document with 3 sections\n    </p>\n</div>\n\n<!-- Intro Text -->\n# Braq\n<b>Customizable data format for config files, AI prompts, and more</b>\n\nThis project is part of the [Pyrustic Open Ecosystem](https://pyrustic.github.io).\n\n\n## Table of contents\n- [Overview](#overview)\n- [Data format specification](#data-format-specification)\n- [Notable use cases](#notable-use-cases)\n    - [Config files](#config-files)\n    - [AI prompts](#ai-prompts)\n    - [Source code documentation](#source-code-documentation)\n- [Classes for interacting with a document](#classes-for-interacting-with-a-document)\n    - [Base document class](#base-document-class)\n    - [File document class](#file-document-class)\n- [Section class](#section-class)\n- [Base functions](#base-functions)\n    - [Parse a document](#parse-a-document)\n    - [Parse a document iteratively](#parse-a-document-iteratively)\n    - [Read a file](#read-a-file)\n    - [Read a file iteratively](#read-a-file-iteratively)\n    - [Render a document](#render-a-document)\n    - [Write to file](#write-to-file)\n- [Braq schema for data validation](#braq-schema-for-data-validation)\n- [Misc functions](#misc-functions)\n- [Miscellaneous](#miscellaneous)\n- [Testing and contributing](#testing-and-contributing)\n- [Installation](#installation)\n\n\n# Overview\n**Braq** (pronounced `/\u02c8b\u0279\u00e6k/`) is a human-readable customizable data format whose reference parser is an eponymous lightweight [Python](https://www.python.org/) library available on [PyPI](#installation).\n\n## Minimal format specification\nA Braq **document** is made up of **sections**, each defined by a **header** surrounded by square brackets (hence the name Braq) and a **body** which is just lines of text.\n\nSince a body is arbitrary text, it is possible to embed a complex [dictionary data structure](https://en.wikipedia.org/wiki/Dictionary_(data_structure)) into a section by encoding it with the human-readable [Paradict](https://github.com/pyrustic/paradict) data format.\n\nIts versatility and minimal format specification make Braq highly customizable and therefore allow it to be used in an eclectic set of use cases such as config files, AI prompts, and code documentation.\n\n## Intuitive programming interface\nThe Braq parser offers an intuitive programming interface to smoothly interact with a Braq document as well as a transparent integration with [Paradict](https://github.com/pyrustic/paradict) for embedding and loading complex dictionary data structures.\n\nBraq provides functions for parsing documents line by line, creating document models, rendering documents, and performing file I/O operations, among other functionalities. \n\nAt a higher level, the `Document` class leverages the base functions to model documents and allow seamless interaction with them. This class also serves as the parent class for `FileDoc` that focuses specifically on documents with associated disk files.\n\n<p align=\"right\"><a href=\"#readme\">Back to top</a></p>\n\n\n# Data format specification\nHere are the specs and recommended practices for a valid and neat Braq document:\n\n- A Braq document, when not empty, can be divided into sections. \n\n- A **section** is made up of two parts: a **header** and a **body**. \n\n- The header is defined on its own line, surrounded by two single [square brackets](https://en.wikipedia.org/wiki/Bracket) (opening and closing brackets respectively). \n\n- The body is what is between two consecutive headers or between a header and the end of the document.\n\n- A section can be defined multiple times in the same document. In this case, the parser will concatenate its bodies from top to bottom.\n\n- A section with an empty header is called an **unnamed section**. \n\n- It is recommended to define no more than a single occurrence of a section in a document.\n\n- When a document contains a single unnamed section, it is recommended to place this section at the top of the document.\n\n- When an unnamed document starts a document, it is recommended to omit its header.\n\n- A dictionary data structure encoded with the human-readable [Paradict](https://github.com/pyrustic/paradict) data format can be safely embedded into a section. This section should then be referenced as a **dict section**.\n\n- It is recommended to put 1 empty line as spacing between two consecutive sections.\n\n\n**Example:**\n\n```\nThis is the unnamed section\nthat starts this document.\n\n[section 1]\nLorem ipsum dolor sit amet, \nconsectetur adipiscing elit.\n\n[section 2]\n# dictionary data structure encoded with Paradict\nid = 42\nuser = \"alex\" \nbooks = (dict)\n    sci-fi = (list)\n        \"book 1\"\n        \"book 2\"\n    thriller = (set)\n        \"book 3\"\n\n[section 1]\nit is not recommended to multiply the occurrences\nof a section, however the parser will append this \noccurrence of 'section 1' to the previous one.\n```\n\n\n<p align=\"right\"><a href=\"#readme\">Back to top</a></p>\n\n# Notable use cases\nThis section outlines three notable use cases for **Braq**, namely config files, AI prompts, and code documentation.\n\n## Config files\nBeing able to embed a dictionary data structure in a section makes Braq de facto suitable for config files.\n\n**Example of a Braq config file:**\n```\nThis is the unnamed section of 'my-config.braq' file.\nThis section will serve as HELP text.\n\n[user]\nid = 42\nname = 'alex'\n\n[gui]\ntheme = 'dark'\nwindow-size = '1024x420'\n```\n\n**Example of code snippet to consume the config file:**\n\n```python\nfrom braq import FileDoc\n\nconfile = FileDoc(\"my-config.braq\")\n\n# build the 'user' dict section\nuser = confile.build(\"user\")\n\n# test\nassert user == {\"id\": 42, \"name\": \"alex\"}\n\n# retrieve the unnamed section\ntext = confile.get(\"\")  # notice the empty header str\n\n# retrieve the 'user' dict section as a text\ntext = confile.get(\"user\")\n\n# embed a 'server' dict section in the config file\nserver_conf = {\"ip-address\": \"127.0.0.1\", \"port\": 80}\nconfile.embed(\"server\", server_conf)  # change persisted\n\n# batch edit mode (changes are persisted at the end)\nwith confile.edit_model():  # by default, autosave==True\n    # perform several changes here !\n    # ...\n    confile.embed(\"gui\", {\"background\": \"red\", \n                          \"size\": 42})\n    confile.remove(\"server\")\n    # ...\n```\n\n> A schema can be passed to a `FileDoc` instance to validate dict sections.\n\n## AI prompts\nThe capability to seamlessly interweave human-readable structured data with prose within a single document is a fundamental capability that a language designed to interact with AI must possess.\n\nAdditionally, the fact that Braq natively supports indentation removes the need for input sanitization, thereby eliminating an entire class of injection attacks.\n\n### Specs\nFollowing are specs for building structured AI prompts with Braq:\n\n- A prompt document must start with the **root instructions** defined inside the top unnamed section.\n- The next section that the AI should actively care about, after the top unnamed section, should be explicitly referenced in the root instructions.\n- User input must be programmatically embedded as a text value of a dictionary key inside a section that is not the top unnamed section.\n\nThat's it ! The specification is deliberately short to avoid unnecessary complexity and also to leave room for creativity.\n\n### Example\n\n```\nYou are an AI assistant, your name is Jarvis.\n\nYou will access the websites defined in the WEB section\nto answer the question that will be submitted to you.\nThe question is stored in the 'input' key of the USER \ndict section.\n\nBe kind and consider the conversation history stored\nin the 'data' key of the HISTORY dict section.\n\n[USER]\ntimestamp = 2024-12-25T16:20:59Z\ninput = (raw)\n    Today, I want you to teach me prompt engineering.\n    Please be concise.\n    ---\n\n[WEB]\nhttps://github.com\nhttps://www.xanadu.net\nhttps://www.wikipedia.org\nhttps://news.ycombinator.com\n\n[HISTORY]\n0 = (dict)\n    timestamp = 2024-12-20T13:10:51Z\n    input = (raw)\n        What is the name of the planet\n        closest to the sun ?\n        ---\n    output = (raw)\n        Mercury is the planet closest\n        to the sun !\n        ---\n1 = (dict)\n    timestamp = 2024-12-22T14:15:54Z\n    input = (raw)\n        What is the largest planet in\n        the solar system?\n        ---\n    output = (raw)\n        Jupiter is the largest planet\n        in the solar system !\n        ---\n```\n\n## Source code documentation\nThe flexibility of Braq gives the possibility to define custom data formats for specific use cases. Source code documentation is one of those use cases that need Braq with a custom format on top of it.\n\nThis is how Braq can be used to document a function:\n\n```python\ndef add(a, b):\n    \"\"\"\n    This function adds together the values of \n    the provided arguments.\n    \n    [params]\n    - a: first integer\n    - b: second integer\n    \n    [return]\n    Returns the sum of `a` and `b`\n    \"\"\"\n    return a + b\n```\n\n> A tool to consume [docstrings](https://en.wikipedia.org/wiki/Docstring) and output browsable Markdown documents is in development.\n\n<p align=\"right\"><a href=\"#readme\">Back to top</a></p>\n\n# Classes for interacting with a document\nThe library exposes the `Document` and `FileDoc` classes for interacting with documents. In contrary to the `Document` class, `FileDoc` focuses specifically on documents with associated disk files such as **config files**.\n\n## Base document class\nThe `Document` class creates an editable model of a Braq document and also offers to validate it with a schema.\n\n**Usage example:**\n\n```python\nfrom braq import Document\n\nINIT_TEXT = \"\"\"\nThis document contains\nconfiguration data\n\n[user]\nid = 42\nname = 'alex'\n\"\"\"\n\nSCHEMA = {\"user\": {\"id\": \"int\", \"name\": \"str\"}}\n\ndocument = Document(INIT_TEXT, schema=SCHEMA)\n\n# get the body of the unnamed section as a text\ntext = document.get(\"\")  # empty header string\n\n# build the 'user' dict section\nuser = document.build(\"user\")\n# test\nassert user == {\"id\": 42, \"name\": \"alex\"}\n\n# set a section (here, we are editing the unnamed section)\ndocument.set(\"\", \"line 1\\nline 2\")\nassert document.get(\"\") == \"line 1\\nline 2\"\n\n# embed a 'server' dict section\nserver_conf = {\"ip-address\": \"127.0.0.1\", \"port\": 80}\ndocument.embed(\"server\", server_conf)\n\n# list headers\nassert document.list_headers() == (\"\", \"user\", \"server\")\n\n# validate specific dict sections\n# (no args implies that the entire doc will be the target)\ndocument.validate(\"user\", \"server\")  # returns a bool\n# beware, the 'validate' method may raise an exception\n# for good reasons !\n```\n\n> There is more to discover about the `Document` class, such as the `clear`, `remove`, and `render` methods, exposed properties, and more.\n\n\n> Check out the documentation for `braq.Document` [here](https://github.com/pyrustic/braq/blob/master/docs/README.md).\n\n\n## File document class\nThe `FileDoc` class is based on the **Document** class and focuses specifically on documents with associated disk files such as **config files**.\n\n> As with the `Document` class, a schema can be passed to a `FileDoc` instance to validate dict sections.\n\n```python\nfrom braq import FileDoc\n\nconfile = FileDoc(\"config-file.braq\")\n\n# build the 'user' section\nuser = confile.build(\"user\")\n\n# test\nassert user == {\"id\": 42, \"name\": \"alex\"}\n\n# retrieve the unnamed section as a text\ntext = confile.get(\"\")  # notice the empty header str\n\n# retrieve the 'user' dict section as a text\ntext = confile.get(\"user\")\n\n# embed a 'server' dict section\nserver_conf = {\"ip-address\": \"127.0.0.1\", \"port\": 80}\nconfile.embed(\"server\", server_conf)  # change persisted\n\n# batch edit mode (changes are persisted at the end)\nwith confile.edit_model():  # by default, autosave==True\n    # perform several changes here !\n    # ...\n    confile.embed(\"gui\", {\"color\": \"blue\"})\n```\n\n> There is more to discover about the **FileDoc** class, such as the `load`, `save`, and `save_to` methods, exposed properties, and more.\n\n> Check out the documentation for `braq.FileDoc` [here](https://github.com/pyrustic/braq/blob/master/docs/README.md).\n\n<p align=\"right\"><a href=\"#readme\">Back to top</a></p>\n\n# Section class\nThe `Section` class is an abstraction representing a Braq section. It exposes the `header` and `body` properties and renders itself when its `__str__` method is called implicitly.\n\n```python\nimport braq\n\n# create a Section object\nheader, body = \"my header\", (\"line a\", \"line b\")\nsection = braq.Section(header, body)\n\n# test the properties\nassert section.header == \"my header\"\nassert section.body == \"line a\\nline b\"\n\n# test the rendering\nassert str(section) == \"\"\"\\\n[my header]\nline a\nline b\"\"\"\n```\n\n<p align=\"right\"><a href=\"#readme\">Back to top</a></p>\n\n# Base functions\nBase classes such as `Document` and `FileDoc` use several public functions under the hood that can be directly called by the programmer at the right time. These basic functions allow you to parse and render documents as well as read and write file documents.\n\n## Parse a document\nThe library exposes the `parse` function which takes as input the text stream to be parsed, then returns a **dictionary** whose keys and values are strings representing headers and bodies respectively.\n\n> Sections sharing the same header are concatenated !\n> The header of an unnamed section is an empty string.\n\n```python\nimport braq\n\ntext = \"\"\"\\\nthis is the unnamed section at\nthe top of this document...\n\n[section 1]\nthis is section 1\"\"\"\n\nd = braq.parse(text)\n\n# check headers\nassert tuple(d.keys()) == (\"\", \"section 1\")\n# check the body of 'section 1'\nassert d[\"section 1\"] == \"this is section 1\"\n```\n\n> Check out the documentation for `braq.parse` [here](https://github.com/pyrustic/braq/blob/master/docs/README.md).\n\n## Parse a document iteratively\nA document can be parsed line by line as following:\n\n```python\nimport braq\n\ntext = \"\"\"\\\nthis is the unnamed section\n\n[section 1]\nthis is section 1\"\"\"\n\nfor header, body in braq.parse_iter(text):\n    if header:\n        print(\"[\" + header + \"]\")\n    for line in body:\n        print(line)\n```\n\nOutput:\n\n```text\nthis is the unnamed section\n\n[section 1]\nthis is section 1\n```\n\n\n> Check out the documentation for `braq.parse_iter` [here](https://github.com/pyrustic/braq/blob/master/docs/README.md).\n\n## Read a file\nThe library exposes the `read` function which takes as input the path to a file to parse, then returns a dictionary whose keys and values are strings representing headers and bodies respectively.\n\n> Sections sharing the same header are concatenated !\n\n```python\nimport braq\n\npath = \"/home/alex/braqfile.txt\"\n\nr = braq.read(path)\nassert tuple(r.keys()) == (\"\", \"section 1\")\n```\n\n> Check out the documentation for `braq.read` [here](https://github.com/pyrustic/braq/blob/master/docs/README.md).\n\n## Read a file iteratively\nA large text file can be parsed line by line as following:\n\n```python\nimport braq\n\npath = \"/home/alex/braqfile.txt\"\n\nfor header, body in braq.read_iter(path):\n    if header:\n        print(\"[\" + header + \"]\")\n    for line in body:\n        print(line)\n```\nOutput:\n\n```text\nthis is the unnamed section\n\n[section 1]\nthis is section 1\n```\n\n> Check out the documentation for `braq.read_iter` [here](https://github.com/pyrustic/braq/blob/master/docs/README.md).\n\n## Render a document\nRendering a document involves transforming Python objects representing sections into Braq text which is a string that can be displayed on the screen or stored in a file.\n\nThe library exposes the `render` function which accepts as input a sequence of sections (either header-body tuples or `Section` objects) and returns a Braq document.\n\n```python\nimport braq\n\n# sections\nsection_1 = braq.Section(\"section 1\", \"line a\\nline b\")\nsection_2 = \"section 2\", \"line c\\nline d\"\nsection_3 = \"section 3\", (\"line e\", \"line f\")\n\n# rendering\nr = braq.render(section_1, section_2, section_3)\n\nprint(r)\n```\n\nOutput:\n\n```text\n[section 1]\nline a\nline b\n\n[section 2]\nline c\nline d\n\n[section 3]\nline e\nline f\n```\n\n> The `render` function also accepts the `spacing` argument which defaults to 1 and represents the number of lines of spacing between two adjacent sections.\n\n\n> Check out the documentation for `braq.render` [here](https://github.com/pyrustic/braq/blob/master/docs/README.md).\n\n## Write to file\nFollowing is a snippet for writting a Braq document to a file:\n\n```python\nimport braq\n\n# sections\nsection_1 = braq.Section(\"\", \"welcome\")\nsection_2 = braq.Section(\"section 2\")\nsection_3 = \"section 3\", (\"line a\", \"line b\")\n\n# path to file\npath = \"/home/alex/braqfile.txt\"\n# write to file\nr = braq.write(section_1, section_2, section_3, dest=path)\n```\nThe contents of the Braq file:\n```text\nwelcome\n\n[section 2]\n\n[section 3]\nline a\nline b\n```\n\n\n> Check out the documentation for `braq.write` [here](https://github.com/pyrustic/braq/blob/master/docs/README.md).\n\n\n<p align=\"right\"><a href=\"#readme\">Back to top</a></p>\n\n# Braq schema for data validation\nDict sections can be validated against a Braq schema. A Braq schema is a Python dictionary object that can be passed to a `Document` or a `FileDoc`. The keys of this dictionary are the headers of dict sections to validate and the values are [Paradict](https://github.com/pyrustic/paradict) schemas.\n\nA Paradict schema is a dictionary containing specs for data validation.\n\nA spec is either simply a string that represents an expected data type, or a `Spec` object that can contain a checking function for complex validation.\n\nSupported spec strings are: `dict`, `list`, `set`, `obj`, `bin`, `bin`, `bool`, `complex`, `date`, `datetime`, `float`, `grid`, `int`, `str`, `time`\n\n**Example:**\n\n```python\nfrom paradict.validator import Spec\nfrom braq import Document\n\n# Braq text with 2 dict sections\nTEXT = \"\"\"\n[user]\nid = 42\nname = 'alex'\n\n[server]\nip-address = \"127.0.0.1\"\nport = 80\n\"\"\"\n\n# Associated schema\nSCHEMA = {\"user\": {\"id\": \"int\",\n                   \"name\": \"str\"},\n          \"server\": {\"ip-address\": \"str\",\n                     \"port\": Spec(\"int\", lambda x: 0 < x < 65535)}}\n\ndoc = Document(TEXT, schema=SCHEMA)\nassert doc.validate()\n# beware, the validate function returns a bool\n# but it can also raises an exception when something is wrong \n```\n\n\n<p align=\"right\"><a href=\"#readme\">Back to top</a></p>\n\n# Misc functions\nThe `check_header` function accepts a line of text as input and then returns a boolean to indicate whether this line is a header or not.\n\n```python\nimport braq\n\nline_1 = \"[my header]\"\nline_2 = \"[this isn't a header] at all\"\nassert braq.check_header(line_1) is True\nassert braq.check_header(line_2) is False\n```\n\nThe `get_header` function accepts a line of text as input and returns a string if the line is a header. Otherwise, `None` is returned.\n\n```python\nimport braq\n\nline_1 = \"[my header]\"\nline_2 = \"[this isn't a header] at all\"\nassert braq.get_header(line_1) == \"my header\"\nassert braq.get_header(line_2) is None\n```\n\n> Check out the documentation for `braq.check_header` and `braq.get_header` [here](https://github.com/pyrustic/braq/blob/master/docs/README.md).\n\n<p align=\"right\"><a href=\"#readme\">Back to top</a></p>\n\n# Miscellaneous\nCollection of miscellaneous notes.\n\n## Cover image\nThe beautiful cover image is generated with [Carbon](https://carbon.now.sh/about).\n\n<p align=\"right\"><a href=\"#readme\">Back to top</a></p>\n\n# Testing and contributing\nFeel free to **open an issue** to report a bug, suggest some changes, show some useful code snippets, or discuss anything related to this project. You can also directly email [me](https://pyrustic.github.io/#contact).\n\n## Setup your development environment\nFollowing are instructions to setup your development environment\n\n```bash\n# create and activate a virtual environment\npython -m venv venv\nsource venv/bin/activate\n\n# clone the project then change into its directory\ngit clone https://github.com/pyrustic/braq.git\ncd braq\n\n# install the package locally (editable mode)\npip install -e .\n\n# run tests\npython -m unittest discover -f -s tests -t .\n\n# deactivate the virtual environment\ndeactivate\n```\n\n<p align=\"right\"><a href=\"#readme\">Back to top</a></p>\n\n# Installation\n**Braq** is **cross-platform**. It is built on [Ubuntu](https://ubuntu.com/download/desktop) and should work on **Python 3.5** or **newer**.\n\n## Create and activate a virtual environment\n```bash\npython -m venv venv\nsource venv/bin/activate\n```\n\n## Install for the first time\n\n```bash\npip install braq\n```\n\n## Upgrade the package\n```bash\npip install braq --upgrade --upgrade-strategy eager\n```\n\n## Deactivate the virtual environment\n```bash\ndeactivate\n```\n\n<p align=\"right\"><a href=\"#readme\">Back to top</a></p>\n\n# About the author\nHello world, I'm Alex, a tech enthusiast ! Feel free to get in touch with [me](https://pyrustic.github.io/#contact) !\n\n<br>\n<br>\n<br>\n\n[Back to top](#readme)\n\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Customizable data format for config files, AI prompts, and more",
    "version": "0.0.5",
    "project_urls": {
        "Homepage": "https://github.com/pyrustic/braq"
    },
    "split_keywords": [
        "data-format",
        "config",
        "configuration",
        "configfile",
        "config-files",
        "customizable",
        "versatile",
        "ai-prompts",
        "pyrustic"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "6c48c40c87f47108633d1898b4fa7fc96b8e714e4c5a91870f7c026f9ac3ab62",
                "md5": "92d7c57bfb3ddc34072be55f293a92a9",
                "sha256": "3ecd6f1454967062c60947f2d673bbcdd3ad44cc95c4a1f7ce58680648f4ee39"
            },
            "downloads": -1,
            "filename": "braq-0.0.5-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "92d7c57bfb3ddc34072be55f293a92a9",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.5",
            "size": 25426,
            "upload_time": "2024-03-13T23:07:46",
            "upload_time_iso_8601": "2024-03-13T23:07:46.465080Z",
            "url": "https://files.pythonhosted.org/packages/6c/48/c40c87f47108633d1898b4fa7fc96b8e714e4c5a91870f7c026f9ac3ab62/braq-0.0.5-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "f24808d05c66ea3e3dc97d8870be862456fa46a0950082e2dd7e046b9e9d63ad",
                "md5": "3fbc94a19c97f86ee3d6087af778c13f",
                "sha256": "ee1323758afd05da9e8d35087929aa57876a948807d21ba43769e9a372619004"
            },
            "downloads": -1,
            "filename": "braq-0.0.5.tar.gz",
            "has_sig": false,
            "md5_digest": "3fbc94a19c97f86ee3d6087af778c13f",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.5",
            "size": 26032,
            "upload_time": "2024-03-13T23:07:49",
            "upload_time_iso_8601": "2024-03-13T23:07:49.227364Z",
            "url": "https://files.pythonhosted.org/packages/f2/48/08d05c66ea3e3dc97d8870be862456fa46a0950082e2dd7e046b9e9d63ad/braq-0.0.5.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-03-13 23:07:49",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "pyrustic",
    "github_project": "braq",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "braq"
}
        
Elapsed time: 0.20261s