{"id":26326460,"url":"https://github.com/alnvdl/fstringen","last_synced_at":"2025-03-15T19:39:47.769Z","repository":{"id":57432433,"uuid":"212883784","full_name":"alnvdl/fstringen","owner":"alnvdl","description":"A text generator based on f-strings.","archived":false,"fork":false,"pushed_at":"2024-03-17T15:48:03.000Z","size":58,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-02T05:12:25.418Z","etag":null,"topics":["code-generator","fstring","python","python3","template-engine"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alnvdl.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-10-04T18:59:00.000Z","updated_at":"2022-07-02T19:13:30.000Z","dependencies_parsed_at":"2022-09-19T08:10:28.893Z","dependency_job_id":null,"html_url":"https://github.com/alnvdl/fstringen","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alnvdl%2Ffstringen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alnvdl%2Ffstringen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alnvdl%2Ffstringen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alnvdl%2Ffstringen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alnvdl","download_url":"https://codeload.github.com/alnvdl/fstringen/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243784101,"owners_count":20347409,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["code-generator","fstring","python","python3","template-engine"],"created_at":"2025-03-15T19:39:47.253Z","updated_at":"2025-03-15T19:39:47.762Z","avatar_url":"https://github.com/alnvdl.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# fstringen\nfstringen (pronounced: f-string-gen) is a library for writing text and code\ngenerators in Python. It builds upon [f-strings](\nhttps://docs.python.org/3/reference/lexical_analysis.html#f-strings) available\nin Python 3.6+, and it is based on two core concepts: models and generators.\n\nfstringen was designed to generate code based on OpenAPI specs, but that is\njust one possible use case. It can take any dictionary-equivalent model\n(including YAML and JSON) and turn that into a browsable model, with\nrudimentary support for cross-references. Generators then transform this model\nin the desired output.\n\nA `Model` is simply a Python dictionary or enumerable (which may be manually\niniatialized or sourced from a YAML or JSON file) representing a hierarchy,\ntypically with deep nesting. The `select` operation is run on `Models`s to\nselect a new sub-`Model` based on a path selection mechanism.\n\nGenerators are functions annotated with the `@gen()` decorator, which gives\nsome extra powers to special f-strings expressions in them: automagic\nindentation, smart list insertion and scope-related hacks. It makes your Python\ncode bear a vague resemblance to JSX code. Generators may also be configured to\nautomatically output to files, with optional header notices.\n\n## Installing\nYou can install directly from PyPI:\n\n    $ pip3 install fstringen --user\n\n## Using\nfstringen is based on special f-strings, called fstringstars: triple-quoted\nf-strings that start and ends with an asterisk (`*`).\n\nThis special syntax indicates to fstringen that the string should be adapted\nwith extra features like automagic indentation, smart list insertion and\nscope-escaping tricks.\n\nA generator that outputs to a file looks like this (this is the `example.py`\nfile in this project):\n\n```py\nfrom fstringen import gen, Model\n\nPREAMBLE = \"// File generated by fstringen. DO NOT EDIT.\\n\\n\"\nmodel = Model(\"example\", {\n    \"structs\": {\n        \"mystruct\": {\n            \"color\": \"string\"\n        },\n        \"anotherstruct\": {\n            \"name\": \"string\",\n            \"age\": \"int\"\n        }\n    }\n})\n\n\n@gen()\ndef gen_struct(struct):\n    fields = [\"{} {}\".format(field.name, field)\n              for field in struct.select(\"*\")]\n\n    return f\"\"\"*\n    type {struct.name} struct {{\n        {fields}\n    }}\n\n    *\"\"\"\n\n\n@gen(model=model, fname=\"myfile.go\", preamble=PREAMBLE)\ndef gen_myfile(model):\n    return f\"\"\"*\n    package main\n\n    // Let's generate some structs!\n    {[gen_struct(struct) for struct in model.select(\"/structs/*\")]}\n    *\"\"\"\n```\n\nAll generator functions using fstringstars must be decorated with `@gen()`.\n\nWhen no parameters are passed to `gen()`, the generator is considerate a\nsubordinate generator (i.e., they need to be called explicitly from other\ngenerators).\n\nWhen the `model` and `fname` arguments are used, the generator becomes a file\ngenerator, which is automatically executed and outputs to that file when the\nPython interpreter exits (i.e., you don't need to explicitly call file\ngenerators).\n\nInside generators, fstringstars can use regular f-string `{expression}`\ninvocations.\n\nThe real power of fstringen comes from `Model`s, which allow easy selection of\ndata:\n\n- Every `Model` has the `select(path, [default])` method, which takes a `path`\n  and returns a new `Model` based on the query that path indicates. Optionally,\n  a `default` value can be passed to `select` for returning when `select' fails\n  to find something.\n- Calling a `Model` directly is a shorthand for `Model.select`. In other words,\n  `myobj(\"/path\")` is the same as `myobj.select(\"/path\")`.\n- Every `Model` has a `name` attribute, corresponding to the path element or\n  array index through which we arrived at that element.\n- If a path ends with `/*` and the preceding path contains a dictionary or\n  enumerable value, a `Model` containing a list of `Model`s is returned,\n  containing all items in that dictionary (as key, value) or enumerable (as\n  index, value).\n- If a path element ends with `-\u003e`, the value contained in that attribute is\n  assumed to contain a path (absolute or relative), and that path is used to\n  look up the referenced object in the same `Model`.\n- Three convenience methods are also available in `Model`s. All of them can\n  take a 'path' to query under that `Model`, of if called without a path, they\n  apply to the `Model` in question:\n  - `is_reference(path)` checks whether a given `Model` contains a reference.\n  - `has(path)` allows for verification of the existence of a path under that\n    `Model`.\n  - `is_enabled(path)` method verifies that the path exists and has a truthy\n    value.\n\nThe two most commonly used imports from `fstringen` are `gen` and `Model`.\n\nFstringstars have one important distiction when compared to regular\ntriple-quoted strings: their first and last `\\n` are discarded when present.\nTherefore, the following are all equivalent:\n\n    fstringstar = f\"\"\"*\n    ...\n    *\"\"\"\n\n    fstringstar = f\"\"\"*...*\"\"\"\n\n    fstringstar = f\"\"\"*\n    ...*\"\"\"\n\n    fstringstar = f\"\"\"*...\n    *\"\"\"\n\nThis design intentional, especially because it enables the first style shown\nabove (newline at the start, newline at the end), which makes generators more\nreadable. Avoid using regular triple-quoted strings in generators to keep\nbehavior more preditable and consistent.\n\nAlso, please note that using single-quotes to define fstringstars is not\nsupported (i.e., `f'''*...*'''` is not a valid fstringstar).\n\n## Caveats\nfstringen does dangerous things with scope and function re-declaration. This\nmeans you should only use it in scripts that are code generators, and code\ngenerators alone (i.e., they don't do anything else). Correctness and safety\nwere sacrificed for neatness and ease-to-use.\n\nSince fstringen tramples over all common sense, pretty much all exceptions are\nintercepted and transformed into custom error messages. Otherwise, because of\nthe scope tricks and function re-declarations, most tracebacks and error\nmessages become useless and confusing.\n\nPython 3.6+ is required. PyYAML is an optional dependency.\n\n## Known issues\nBecause of Python limitations, a few things are not possible:\n\n**Quotes in fstringstars strings**\n\nJust as you can't have a triple-quoted string that starts or ends with quotes\nin Python:\n\n    my_str = \"\"\"\"a\"\"\"\"\n\nYou can't have a fstringstar like this:\n\n    my_fstringstar = f\"\"\"*\"a\"*\"\"\"\n\nThat's because Python can't figure out how that string starts or ends\n(fstringstars are compiled to triple-quoted Python f-strings). You can achieve\nthe same result by escaping quotes with `//` when they start or end a string:\n\n    my_fstringstar = f\"\"\"*\\\\\"a\\\\\"*\"\"\"\n\n**Don't compare with `is` and avoid `isinstance`**\n\nWhen dealing with a `Model`, don't use the `is` comparison operator. Consider\nthe following code:\n\n    mybool = model.select(\"/path/to/a/bool\")\n\nWhen checking whether `mybool` is `True` or `False`, do it using `==` or if in\na conditional, just check the value directly without a comparison\n(`if mybool`). The same applies to `None`.\n\nThe reason for this limitation is that `select` always returns a `Model`, and a\n`Model` can never be compared to Python objects using the `is` operator, which\nverifies that two expressions point to the same object.\nHowever, equality operators (`==` and `!=`) work just fine because `Model`\napplies some magic to make that work.\n\nBecause `NoneType` and `bool` cannot be subclassed in Python, a `Model` isn't\nable to inherit from those (as it does for `int`, `str`, `list`, `dict`, etc.).\nFor that reason, you should also avoid using `isinstance`. Instead, you can\nverify the original type for a value by checking the `type` attribute in a\n`Model`.\n\n**Variable scoping in list comprehensions**\n\nList comprehensions have their own frame and local scope in Python 3+, and the\nscope-escaping tricks fstringen uses don't work in them.\n\nSo if you have code like this:\n\n    myvar = \"myvalue\"\n\n    return f\"\"\"*\n    ...\n\n    {[do_something(entity, myvar) for entity in model.select(\"/entities/*\")]}\n    *\"\"\"\n\nIt will not work, because `myvar` will not be accesible to that list\ncomprehension. To work around this, you can either have the list comprehension\noutside the fstringstar, or directly embed the variable's value in the list\ncomprehension expression.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falnvdl%2Ffstringen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falnvdl%2Ffstringen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falnvdl%2Ffstringen/lists"}