wtfl


Namewtfl JSON
Version 1.2.1 PyPI version JSON
download
home_pagehttps://github.com/evtn/wtfl
SummaryWell-designed Text-based Friendly Language
upload_time2023-06-29 18:59:30
maintainer
docs_urlNone
authorDmitry Gritsenko
requires_python>=3.7,<4.0
licenseMIT
keywords markup config
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # WTFL — Well-designed Text-based Friendly Language

This is a spec for a very well-designed declarative language and a Python package to work with it.    
Obviously, current solutions for config et al. (JSON, YAML, TOML) are very unsuitable as software development progress is going on, so here I propose a brand new format.   

WTFL has all the features of its predecessors, and much more, with a very well-designed friendly syntax.

It is case-insensitive, obvious and feature-rich language.

Here is an example of the format:

```wtfl
...This is a comment

key's "value"

weight of apple is 123
```

This is equivalent to this JSON:

```json
{
    "key": "value",
    "apple": {
        "weight": 123
    }
}
```

# Package

Package's API is similar to built-in `json`:

read an object from a string:
```python
def wtfl.loads(
    s, # string to load
    *,
    parse_float, # function for float parsing, `float` used by default
    parse_int, # function for integer parsing (only unprefixed decimal), `int` used by default
    parse_roman, # function for roman numerals parsing, accepts whole literal as a string (0r...)
    parse_numbers, # function for integer literals parsing (0b..., 0o..., and so on)
) -> 
```
read an object from a file (same argument meaning as `.loads`):    
`wtfl.load(file, *, parse_float, parse_int, parse_roman, parse_numbers)` 

dump an object into a string:
```python
def wtfl.dumps(
    obj: object, # object to dump
    *,
    # if True, non-serializable keys / values are skipped
    skipkeys: bool = False, 
    
    # if True, encodes non-ASCII characters
    ensure_ascii: bool = True, 
    
    # if a non-negative integer, used as indent size. if a string, used as indent character. If None, everything is inlined
    indent: int | str | None = 2, 
    
    # a function that is used to recover from serialization errors. 
    # if current value is not serializable and skipkeys=False, tries to serialize the result of default(value)
    default: Callable[[object], str] | None = None, 
    
    # if True, sorts object keys
    sort_keys: bool = False,
)
```
dump an object into a file (same argument meaning as `.dumps()`):    
`wtfl.dump(file, obj, *, skipkeys, ensure_ascii, indent, default, sort_keys)`

# Reserved keywords

It is very important to know all the keywords of WTFL, since all those keywords are important.    

Here's a list (keywords in the same list entry are equivalent and used interchangeably in the spec):

- `is` / `are` / `'s` / `'re` / `do` / `does` / `be`
- `isn't` / `aren't` / `'sn't` / `'ren't`
- `of`
- `also` / `and also` / `but also`
- `that` / `this` / `these` / `those`
- `there`
- `have` / `has` / `'ve`
- `haven't` / `hasn't` / `'ven't`
- `can`
- `cannot` / `can't`
- `true` / `falsen't`
- `false` / `truen't`
- `and`
- `return`
- `skip`
- `stay`
- `to`

You can use keywords as names (except true / false / haven't), this list is just so you know them all.

# Keys

Keys are at the center of the language. In WTFL, keys are defined in two ways:

1. Same as values. Provide a value and it will be converted to string.
2. As bare name. A bare name should start with any char of `[A-Za-z_-]` and consist of chars in `[A-Za-z0-9_-]`.

Any key can have optional piece preceding it. Possible choices are: `a`, `an`, `the`, `de`, `du`, `le`, `la`, `les`, `des`, `but` and `um`.

Here are some examples:

```wtfl
32 is 32
0x45 is 0x45
4.5's 4.5
"key2" be "key2"
the jasdofia913247 is "what?"
a mogu's "sus"
```

It's equivalent to this JSON:

```json
{
    "32": 32,
    "69": 69,
    "4.5": 4.5,
    "key2": "key2",
    "jasdofia913247": "what?",
    "mogu": "sus"
}
```

# Inline

```
Many formats, such as TOML, don't allow writing everything in one line. That's a shame, since, as we all know, writing everything in one line greatly improves readability and this block is a living proof of that rule. You can easily read everything written here without any discomfort, so why restrict a language to multiple lines?
```

Since inlining is so good, WTFL introduces it in a very simple manner, just write everything in one line:

```wtfl
apple does have weight is 123 color is "red" that is everything you need to know about apples but also key is 123
```
(With one exception: array/object definitions have to end in newline or `also`)


Is equivalent to this JSON:

```json
{
    "apple": {
        "weight": 123,
        "color": "red"
    },
    "key": 123
}
```

# Values

## Setting values

Setting values to keys is straightforward using `is` (or `are` or any other alias):

```wtfl
key is 35
key2 be 0x56
```

This sets "key" to 35. But there are various other ways.

For example, if you are sure key has to have some value, use `has to be` or `have to be`:

```wtfl
key has to be 35

key is 36 ...no!!!! this would raise some error.
```

If you want to say the key can have some value, use `can be`:

```wtfl
key can be 35

key is 36 ...well, okay, good luck next time
```

...or `can't be` / `cannot be` for opposite meaning:

```wtfl
key can't be 35

key is 35 ...what? you just said it can't be! error here
```

You also can just allow and restrict keys:
```wtfl
key can be
key2 can't be

key is 23 ...okay
key2 is 23 ...nope
```

Be sure to not mess up the order (see Time Travel section for workarounds):

```wtfl
key is 23

key can't be 23 ...produces a warning "Too late, it's already done", but no error (since it's already done)
```

Setting key several times makes a lot of sense, but only the last value is preserved (see Time Travel section for workarounds)

```wtfl
key is 23
key is 35

...The key is 35 now
```

## Types

### Numbers

There are decimal integer literals, such as `102`, `-4`, `0`, and, as expected, some other:

- Binary (2) with `0b` prefix: `0b10010`
- Octal (8) with `0o` prefix: `0o755`
- Decimal (10) with `0d` prefix: `0d102`
- Duodecimal (12) with `0z` prefix: `0z9a1`
- Vigesimal (20) with `0v` prefix: `0vjija`
- Roman numerals with `0r` prefix: `0rXIMI`

Floats are also supported: `0.1`, `2.`, `.2`, `2.3e4`, `2.3e4`

### Strings

String literals are enclosed in double quotes, supporting all the usual Python escape sequences:

```wtfl
sus is "amogus"
```

### None / null

...is represented by `haven't` keyword:

```wtfl
value is haven't
```

Equivalent to:

```json
{
    "value": null
}
```

### Boolean

That type is very simple: You have `true` / `falsen't`, and you have `false` / `truen't`

### Objects

Nested structures are often needed, so WTFL has those!

Suppose you have this JSON:

```json
{
    "apple": {
        "weight": 123,
        "color": "red"
    }
}

```

Here's how you define this complex object with WTFL, using `have` / `has` keyword:

```wtfl
apple does have
    weight is 123
    color is "red"
that's all folks!
```
Indentation is optional, as well as the exclamation mark after "that's all folks".
In fact, you can use any line to end the object, as long as it starts with `(that|there)`:

```wtfl
that's all
that is everything, folks
there's nothing more I think
there are no more keys, go home
there it is, the end of the object!
```

Be aware that you cannot use `also` in that line (see Inline section for more info)

If you want something less structured, you can define keys one-by-one:

```
weight of apple is 123
color of apple is "red"
```

### Arrays

As any good format, WTFL has arrays. Arrays are defined very straightforwardly:

```wtfl
apple_crate does have
    has
        weight is 123
        color is "red"
    that was the object
    
    23 ...what? a number in apple crate? okay...
        
that was the array
```

Equivalent JSON:

```json
{
    "apple_crate": [
        {
            "weight": 123,
            "color": "red"
        },
        23
    ]
}
```

Be aware that...

```wtfl
has
that's all
```

...is an empty object. If you want an empty list, use:

```wtfl
has 0
```

If you create an array and then add a non-integer key, it will turn into an object:

```wtfl
apple_crate does have
    has
        weight is 123
        color is "red"
    that was the object
    
    23 ...what? a number in apple crate? okay...
        
that was the array

frog of apple_crate is 10
```

Produces:

```json
{
    "apple_crate": {
        "0": {
          "weight": 123,
          "color": "red"
        },
        "1": 23,
        "frog": 10
      }
}
```

Keys less than 0 are ignored, keys greater than array length are added, but moved so that there's no holes in the resulting array.


# Advanced features

## Time travel

It is very obvious that there has to be a time travel feature in a modern config format.    
You can travel to the past, to the future, and (experimental) to the present

### Past

To travel to the past, use `return` keyword:

```wtfl
key is 24

...1 is offset in statements. Your statement will be transported right before `key is 24`
return 1 and key can't be 24 
```

This would raise an error, because key can't be 24 at line 1

### Future

To travel to the future, use `skip` keyword:

```wtfl
skip 2 and key is 35

key is 24
```

This would set key to 35, because statement 0 is transported two statements forward, after `key is 35`. 

### Present

This is highly experimental. Use at your own risk.

You can stay in the present (not travelling anywhere)

```wtfl
stay and key is 35

key is 24
```

### Possible problems

1. If you travel back in time and kill your parents, you will never be born
    This is sad, but doesn't influence WTFL
    
2. If you travel back in time and kill my parents, I will never be born
    Please don't exploit this critical vulnerability

3. If you travel in the same line several times, you will create a chain of events inside a single time point. Maybe that's what you want, maybe all bees are aliens. I can't know everything.



# Caveats

- I've decided to not add dates / time support, because of the time travel (and possibly date travel)
            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/evtn/wtfl",
    "name": "wtfl",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.7,<4.0",
    "maintainer_email": "",
    "keywords": "markup,config",
    "author": "Dmitry Gritsenko",
    "author_email": "k01419q45@ya.ru",
    "download_url": "https://files.pythonhosted.org/packages/93/65/87267cae416ec922548a08045d5b7ee6ed4c8197e2f1045bd47c0ea4f270/wtfl-1.2.1.tar.gz",
    "platform": null,
    "description": "# WTFL \u2014 Well-designed Text-based Friendly Language\n\nThis is a spec for a very well-designed declarative language and a Python package to work with it.    \nObviously, current solutions for config et al. (JSON, YAML, TOML) are very unsuitable as software development progress is going on, so here I propose a brand new format.   \n\nWTFL has all the features of its predecessors, and much more, with a very well-designed friendly syntax.\n\nIt is case-insensitive, obvious and feature-rich language.\n\nHere is an example of the format:\n\n```wtfl\n...This is a comment\n\nkey's \"value\"\n\nweight of apple is 123\n```\n\nThis is equivalent to this JSON:\n\n```json\n{\n    \"key\": \"value\",\n    \"apple\": {\n        \"weight\": 123\n    }\n}\n```\n\n# Package\n\nPackage's API is similar to built-in `json`:\n\nread an object from a string:\n```python\ndef wtfl.loads(\n    s, # string to load\n    *,\n    parse_float, # function for float parsing, `float` used by default\n    parse_int, # function for integer parsing (only unprefixed decimal), `int` used by default\n    parse_roman, # function for roman numerals parsing, accepts whole literal as a string (0r...)\n    parse_numbers, # function for integer literals parsing (0b..., 0o..., and so on)\n) -> \n```\nread an object from a file (same argument meaning as `.loads`):    \n`wtfl.load(file, *, parse_float, parse_int, parse_roman, parse_numbers)` \n\ndump an object into a string:\n```python\ndef wtfl.dumps(\n    obj: object, # object to dump\n    *,\n    # if True, non-serializable keys / values are skipped\n    skipkeys: bool = False, \n    \n    # if True, encodes non-ASCII characters\n    ensure_ascii: bool = True, \n    \n    # if a non-negative integer, used as indent size. if a string, used as indent character. If None, everything is inlined\n    indent: int | str | None = 2, \n    \n    # a function that is used to recover from serialization errors. \n    # if current value is not serializable and skipkeys=False, tries to serialize the result of default(value)\n    default: Callable[[object], str] | None = None, \n    \n    # if True, sorts object keys\n    sort_keys: bool = False,\n)\n```\ndump an object into a file (same argument meaning as `.dumps()`):    \n`wtfl.dump(file, obj, *, skipkeys, ensure_ascii, indent, default, sort_keys)`\n\n# Reserved keywords\n\nIt is very important to know all the keywords of WTFL, since all those keywords are important.    \n\nHere's a list (keywords in the same list entry are equivalent and used interchangeably in the spec):\n\n- `is` / `are` / `'s` / `'re` / `do` / `does` / `be`\n- `isn't` / `aren't` / `'sn't` / `'ren't`\n- `of`\n- `also` / `and also` / `but also`\n- `that` / `this` / `these` / `those`\n- `there`\n- `have` / `has` / `'ve`\n- `haven't` / `hasn't` / `'ven't`\n- `can`\n- `cannot` / `can't`\n- `true` / `falsen't`\n- `false` / `truen't`\n- `and`\n- `return`\n- `skip`\n- `stay`\n- `to`\n\nYou can use keywords as names (except true / false / haven't), this list is just so you know them all.\n\n# Keys\n\nKeys are at the center of the language. In WTFL, keys are defined in two ways:\n\n1. Same as values. Provide a value and it will be converted to string.\n2. As bare name. A bare name should start with any char of `[A-Za-z_-]` and consist of chars in `[A-Za-z0-9_-]`.\n\nAny key can have optional piece preceding it. Possible choices are: `a`, `an`, `the`, `de`, `du`, `le`, `la`, `les`, `des`, `but` and `um`.\n\nHere are some examples:\n\n```wtfl\n32 is 32\n0x45 is 0x45\n4.5's 4.5\n\"key2\" be \"key2\"\nthe jasdofia913247 is \"what?\"\na mogu's \"sus\"\n```\n\nIt's equivalent to this JSON:\n\n```json\n{\n    \"32\": 32,\n    \"69\": 69,\n    \"4.5\": 4.5,\n    \"key2\": \"key2\",\n    \"jasdofia913247\": \"what?\",\n    \"mogu\": \"sus\"\n}\n```\n\n# Inline\n\n```\nMany formats, such as TOML, don't allow writing everything in one line. That's a shame, since, as we all know, writing everything in one line greatly improves readability and this block is a living proof of that rule. You can easily read everything written here without any discomfort, so why restrict a language to multiple lines?\n```\n\nSince inlining is so good, WTFL introduces it in a very simple manner, just write everything in one line:\n\n```wtfl\napple does have weight is 123 color is \"red\" that is everything you need to know about apples but also key is 123\n```\n(With one exception: array/object definitions have to end in newline or `also`)\n\n\nIs equivalent to this JSON:\n\n```json\n{\n    \"apple\": {\n        \"weight\": 123,\n        \"color\": \"red\"\n    },\n    \"key\": 123\n}\n```\n\n# Values\n\n## Setting values\n\nSetting values to keys is straightforward using `is` (or `are` or any other alias):\n\n```wtfl\nkey is 35\nkey2 be 0x56\n```\n\nThis sets \"key\" to 35. But there are various other ways.\n\nFor example, if you are sure key has to have some value, use `has to be` or `have to be`:\n\n```wtfl\nkey has to be 35\n\nkey is 36 ...no!!!! this would raise some error.\n```\n\nIf you want to say the key can have some value, use `can be`:\n\n```wtfl\nkey can be 35\n\nkey is 36 ...well, okay, good luck next time\n```\n\n...or `can't be` / `cannot be` for opposite meaning:\n\n```wtfl\nkey can't be 35\n\nkey is 35 ...what? you just said it can't be! error here\n```\n\nYou also can just allow and restrict keys:\n```wtfl\nkey can be\nkey2 can't be\n\nkey is 23 ...okay\nkey2 is 23 ...nope\n```\n\nBe sure to not mess up the order (see Time Travel section for workarounds):\n\n```wtfl\nkey is 23\n\nkey can't be 23 ...produces a warning \"Too late, it's already done\", but no error (since it's already done)\n```\n\nSetting key several times makes a lot of sense, but only the last value is preserved (see Time Travel section for workarounds)\n\n```wtfl\nkey is 23\nkey is 35\n\n...The key is 35 now\n```\n\n## Types\n\n### Numbers\n\nThere are decimal integer literals, such as `102`, `-4`, `0`, and, as expected, some other:\n\n- Binary (2) with `0b` prefix: `0b10010`\n- Octal (8) with `0o` prefix: `0o755`\n- Decimal (10) with `0d` prefix: `0d102`\n- Duodecimal (12) with `0z` prefix: `0z9a1`\n- Vigesimal (20) with `0v` prefix: `0vjija`\n- Roman numerals with `0r` prefix: `0rXIMI`\n\nFloats are also supported: `0.1`, `2.`, `.2`, `2.3e4`, `2.3e4`\n\n### Strings\n\nString literals are enclosed in double quotes, supporting all the usual Python escape sequences:\n\n```wtfl\nsus is \"amogus\"\n```\n\n### None / null\n\n...is represented by `haven't` keyword:\n\n```wtfl\nvalue is haven't\n```\n\nEquivalent to:\n\n```json\n{\n    \"value\": null\n}\n```\n\n### Boolean\n\nThat type is very simple: You have `true` / `falsen't`, and you have `false` / `truen't`\n\n### Objects\n\nNested structures are often needed, so WTFL has those!\n\nSuppose you have this JSON:\n\n```json\n{\n    \"apple\": {\n        \"weight\": 123,\n        \"color\": \"red\"\n    }\n}\n\n```\n\nHere's how you define this complex object with WTFL, using `have` / `has` keyword:\n\n```wtfl\napple does have\n    weight is 123\n    color is \"red\"\nthat's all folks!\n```\nIndentation is optional, as well as the exclamation mark after \"that's all folks\".\nIn fact, you can use any line to end the object, as long as it starts with `(that|there)`:\n\n```wtfl\nthat's all\nthat is everything, folks\nthere's nothing more I think\nthere are no more keys, go home\nthere it is, the end of the object!\n```\n\nBe aware that you cannot use `also` in that line (see Inline section for more info)\n\nIf you want something less structured, you can define keys one-by-one:\n\n```\nweight of apple is 123\ncolor of apple is \"red\"\n```\n\n### Arrays\n\nAs any good format, WTFL has arrays. Arrays are defined very straightforwardly:\n\n```wtfl\napple_crate does have\n    has\n        weight is 123\n        color is \"red\"\n    that was the object\n    \n    23 ...what? a number in apple crate? okay...\n        \nthat was the array\n```\n\nEquivalent JSON:\n\n```json\n{\n    \"apple_crate\": [\n        {\n            \"weight\": 123,\n            \"color\": \"red\"\n        },\n        23\n    ]\n}\n```\n\nBe aware that...\n\n```wtfl\nhas\nthat's all\n```\n\n...is an empty object. If you want an empty list, use:\n\n```wtfl\nhas 0\n```\n\nIf you create an array and then add a non-integer key, it will turn into an object:\n\n```wtfl\napple_crate does have\n    has\n        weight is 123\n        color is \"red\"\n    that was the object\n    \n    23 ...what? a number in apple crate? okay...\n        \nthat was the array\n\nfrog of apple_crate is 10\n```\n\nProduces:\n\n```json\n{\n    \"apple_crate\": {\n        \"0\": {\n          \"weight\": 123,\n          \"color\": \"red\"\n        },\n        \"1\": 23,\n        \"frog\": 10\n      }\n}\n```\n\nKeys less than 0 are ignored, keys greater than array length are added, but moved so that there's no holes in the resulting array.\n\n\n# Advanced features\n\n## Time travel\n\nIt is very obvious that there has to be a time travel feature in a modern config format.    \nYou can travel to the past, to the future, and (experimental) to the present\n\n### Past\n\nTo travel to the past, use `return` keyword:\n\n```wtfl\nkey is 24\n\n...1 is offset in statements. Your statement will be transported right before `key is 24`\nreturn 1 and key can't be 24 \n```\n\nThis would raise an error, because key can't be 24 at line 1\n\n### Future\n\nTo travel to the future, use `skip` keyword:\n\n```wtfl\nskip 2 and key is 35\n\nkey is 24\n```\n\nThis would set key to 35, because statement 0 is transported two statements forward, after `key is 35`. \n\n### Present\n\nThis is highly experimental. Use at your own risk.\n\nYou can stay in the present (not travelling anywhere)\n\n```wtfl\nstay and key is 35\n\nkey is 24\n```\n\n### Possible problems\n\n1. If you travel back in time and kill your parents, you will never be born\n    This is sad, but doesn't influence WTFL\n    \n2. If you travel back in time and kill my parents, I will never be born\n    Please don't exploit this critical vulnerability\n\n3. If you travel in the same line several times, you will create a chain of events inside a single time point. Maybe that's what you want, maybe all bees are aliens. I can't know everything.\n\n\n\n# Caveats\n\n- I've decided to not add dates / time support, because of the time travel (and possibly date travel)",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Well-designed Text-based Friendly Language",
    "version": "1.2.1",
    "project_urls": {
        "Homepage": "https://github.com/evtn/wtfl",
        "Repository": "https://github.com/evtn/wtfl"
    },
    "split_keywords": [
        "markup",
        "config"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "fafc7732c619bbfa146e1af01d05d9b49deb9193a9c5282dd3550595946c9dea",
                "md5": "ca7b38b72b1760b58951ddd9772bb5a7",
                "sha256": "255e152c3e75cc7f012f928d1c2e9b588ad0699f8745197e6b19f582671ee105"
            },
            "downloads": -1,
            "filename": "wtfl-1.2.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "ca7b38b72b1760b58951ddd9772bb5a7",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7,<4.0",
            "size": 14009,
            "upload_time": "2023-06-29T18:59:29",
            "upload_time_iso_8601": "2023-06-29T18:59:29.178296Z",
            "url": "https://files.pythonhosted.org/packages/fa/fc/7732c619bbfa146e1af01d05d9b49deb9193a9c5282dd3550595946c9dea/wtfl-1.2.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "936587267cae416ec922548a08045d5b7ee6ed4c8197e2f1045bd47c0ea4f270",
                "md5": "d0e4bb0aa60026fc40945193ba49a10b",
                "sha256": "4a57069bcb1be177ac8ba30b51e138a1c895be034b517cc2f07f0d4102c72fa9"
            },
            "downloads": -1,
            "filename": "wtfl-1.2.1.tar.gz",
            "has_sig": false,
            "md5_digest": "d0e4bb0aa60026fc40945193ba49a10b",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7,<4.0",
            "size": 16007,
            "upload_time": "2023-06-29T18:59:30",
            "upload_time_iso_8601": "2023-06-29T18:59:30.879513Z",
            "url": "https://files.pythonhosted.org/packages/93/65/87267cae416ec922548a08045d5b7ee6ed4c8197e2f1045bd47c0ea4f270/wtfl-1.2.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-06-29 18:59:30",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "evtn",
    "github_project": "wtfl",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "wtfl"
}
        
Elapsed time: 0.08320s