<commit_before># textX meta-models

textX meta-model is a Python object that knows about all classes that can be
instantiated while parsing the input. A meta-model is built from the grammar by
the functions `metamodel_from_file` or `metamodel_from_str` in the
`textx.metamodel` module.

    from textx import metamodel_from_file
    my_metamodel = metamodel_from_file('my_grammar.tx')

Each rule from the grammar will result in a Python class kept in the meta-model.
Besides, meta-model knows how to parse the input strings and convert them
to [model](model.md).

Parsing the input and creating the model is done by `model_from_file` and
`model_from_str` methods of the meta-model object:

    my_model = my_metamodel.model_from_file('some_input.md')

When parsing a model file or string a new parser is cloned for each model.
This parser can be accessed via the model attribute `_tx_parser`.

!!! warning

    textX accepts unicode strings only so `metamodel_from_str` parameter should be
    `str` for Python 3.x or `unicode` for Python 2.x. That is true for all API
    parameters where string is accepted. The easiest way for Python 2.x is to use
    `from __future__ import unicode_literals` at the top of the file.

## Custom classes

For each grammar rule a Python class with the same name is created dynamically.
These classes are instantiated during the parsing of the input string/file to
create a graph of python objects, a.k.a. `model` or Abstract-Syntax Tree (AST).

Most of the time dynamically created classes will be sufficient, but sometimes
you will want to use your own classes instead. To do so use parameter `classes`
during the meta-model instantiation. This parameter is a list of your classes
that should be named the same as the rules from the grammar which they
represent.

    from textx import metamodel_from_str

    grammar = '''
    EntityModel:
      entities+=Entity    // each model has one or more entities
    ;

    Entity:
      'entity' name=ID '{'
        attributes+=Attribute     // each entity has one or more attributes
      '}'
    ;

    Attribute:
      name=ID ':' type=[Entity]   // type is a reference to an entity. There are
                                  // built-in entities registered on the meta-model
                                  // for primitive types (integer, string)
    ;
    '''

    class Entity(object):
      def __init__(self, parent, name, attributes):
        self.parent = parent
        self.name = name
        self.attributes = attributes


    # Use our Entity class. "Attribute" class will be created dynamically.
    entity_mm = metamodel_from_str(grammar, classes=[Entity])

Now `entity_mm` can be used to parse the input models where our `Entity` class
will be instantiated to represent each `Entity` rule from the grammar.

!!! note
    Constructor of the user-defined classes should accept all attributes defined
    by the corresponding rule from the grammar. In the previous example, we have
    provided `name` and `attributes` attributes from the `Entity` rule. If the
    class is a child in a parent-child relationship (see the next section), then
    the `parent` constructor parameter should also be given.


## Parent-child relationships

There is often an intrinsic parent-child relationship between object in the
model. In the previous example, each `Attribute` instance will always be a child
of some `Entity` object.

textX gives automatic support for these relationships by providing the `parent`
attribute on each child object.

When you navigate [model](model.md) each child instance will have a `parent`
attribute.

!!! note
    Always provide the parent parameter in user-defined classes for each class
    that is a child in a parent-child relationship.


## Processors

To specify static semantics of the language textX uses a concept called
**processor**. Processors are python callables that can modify the model
elements during model parsing/instantiation or do some additional checks that
are not possible to do by the grammar alone.

There are two types of processors:

- **model processors** - are callables that are called at the end of the parsing
  when the whole model is instantiated. These processors accept the model <commit_msg>Extend docs on custom classes to mention postponed init<commit_after># textX meta-models

textX meta-model is a Python object that knows about all classes that can be
instantiated while parsing the input. A meta-model is built from the grammar by
the functions `metamodel_from_file` or `metamodel_from_str` in the
`textx.metamodel` module.

    from textx import metamodel_from_file
    my_metamodel = metamodel_from_file('my_grammar.tx')

Each rule from the grammar will result in a Python class kept in the meta-model.
Besides, meta-model knows how to parse the input strings and convert them
to [model](model.md).

Parsing the input and creating the model is done by `model_from_file` and
`model_from_str` methods of the meta-model object:

    my_model = my_metamodel.model_from_file('some_input.md')

When parsing a model file or string a new parser is cloned for each model.
This parser can be accessed via the model attribute `_tx_parser`.

!!! warning

    textX accepts unicode strings only so `metamodel_from_str` parameter should be
    `str` for Python 3.x or `unicode` for Python 2.x. That is true for all API
    parameters where string is accepted. The easiest way for Python 2.x is to use
    `from __future__ import unicode_literals` at the top of the file.

## Custom classes

For each grammar rule a Python class with the same name is created dynamically.
These classes are instantiated during the parsing of the input string/file to
create a graph of python objects, a.k.a. `model` or Abstract-Syntax Tree (AST).

Most of the time dynamically created classes will be sufficient, but sometimes
you will want to use your own classes instead. To do so use parameter `classes`
during the meta-model instantiation. This parameter is a list of your classes
that should be named the same as the rules from the grammar which they
represent.

    from textx import metamodel_from_str

    grammar = '''
    EntityModel:
      entities+=Entity    // each model has one or more entities
    ;

    Entity:
      'entity' name=ID '{'
        attributes+=Attribute     // each entity has one or more attributes
      '}'
    ;

    Attribute:
      name=ID ':' type=[Entity]   // type is a reference to an entity. There are
                                  // built-in entities registered on the meta-model
                                  // for primitive types (integer, string)
    ;
    '''

    class Entity(object):
      def __init__(self, parent, name, attributes):
        self.parent = parent
        self.name = name
        self.attributes = attributes


    # Use our Entity class. "Attribute" class will be created dynamically.
    entity_mm = metamodel_from_str(grammar, classes=[Entity])

Now `entity_mm` can be used to parse the input models where our `Entity` class
will be instantiated to represent each `Entity` rule from the grammar.

!!! note
    Constructor of the user-defined classes should accept all attributes defined
    by the corresponding rule from the grammar. In the previous example, we have
    provided `name` and `attributes` attributes from the `Entity` rule. If the
    class is a child in a parent-child relationship (see the next section), then
    the `parent` constructor parameter should also be given.

Classes that use `__slots__` are supported. Also, initialization of custom
classes is postponed during model loading and done after reference resolving but
before object processors call (see [Using the scope provider to modify a
model](scoping.md##using-the-scope-provider-to-modify-a-model)) to ensure that
immutable objects (e.g. using [attr frozen
feature](https://www.attrs.org/en/stable/examples.html#immutability)), that
can't be changed after initialization, are also supported.


## Parent-child relationships

There is often an intrinsic parent-child relationship between object in the
model. In the previous example, each `Attribute` instance will always be a child
of some `Entity` object.

textX gives automatic support for these relationships by providing the `parent`
attribute on each child object.

When you navigate [model](model.md) each child instance will have a `parent`
attribute.

!!! note
    Always provide the parent parameter in user-defined classes for each class
    that is a child in a parent-child relationship.


## Processors

To specify static semantics of the language textX uses a concept called
**processor**. Processors are python callables that can modify the model
elements during model parsing/instantiation or do some additional checks that
are not possible to do by the grammar alone.

There are two types of processors:

- **model processors** - are callables that are called at the end of the parsing
  when the whole model is instantiated. These processors accept the model 
{'fraction_non_alphanumeric': 0.05670616901096467, 'fraction_numerical': 0.0006645254180972422, 'mean_word_length': 3.5652173913043477, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 1, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1021232', 'n_tokens_mistral': 2378, 'n_tokens_neox': 2239, 'n_words': 1198}