Skip to content

Commit

Permalink
close #104
Browse files Browse the repository at this point in the history
  • Loading branch information
laowantong committed Nov 20, 2023
1 parent 95b1cd2 commit cbdcc08
Show file tree
Hide file tree
Showing 25 changed files with 1,784 additions and 1,204 deletions.
Binary file added doc/examples/ullman_cthrsg_mcd_sans_cif_80.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1,362 changes: 803 additions & 559 deletions doc/fr_refman.html

Large diffs are not rendered by default.

1,333 changes: 772 additions & 561 deletions doc/fr_refman.ipynb

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion index.php
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@
</form>
</div>
<div id="navigation">
<a target="_blank" href="https://github.com/laowantong/mocodo">Mocodo 4.1.0</a>
<a target="_blank" href="https://github.com/laowantong/mocodo">Mocodo 4.1.1</a>
&nbsp;∙&nbsp;
<a target="_blank" href="https://rawgit.com/laowantong/mocodo/master/doc/fr_refman.html">Documentation</a>
&nbsp;∙&nbsp;
Expand Down
4 changes: 4 additions & 0 deletions mocodo/argument_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,10 @@ def parsed_arguments():
action="store_true",
help=_("raise an error when horizontal or vertical legs overlap"),
)
aspect_group.add_argument("--no_assoc_ids",
action="store_true",
help=_("forbid the use of identifiers in associations (according to the Merise standard)"),
)
aspect_group.add_argument("--gutters",
metavar="STR",
nargs="+",
Expand Down
4 changes: 4 additions & 0 deletions mocodo/association.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ def __init__(self, clause, **params):
for attr in clause.get("attrs", []):
if attr.get("attribute_label", "") == "":
self.attributes.append(PhantomAttribute(attr))
elif attr.get("id_mark", "") == "_":
if params.get("no_assoc_ids"):
raise MocodoError(52, _('The association "{name}" cannot have an identifier.').format(name=self.raw_name))
self.attributes.append(StrongAttribute(attr))
else:
self.attributes.append(SimpleAssociationAttribute(attr))
df_label = params.get("df", "DF")
Expand Down
14 changes: 8 additions & 6 deletions mocodo/convert/relations.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def set_defaults(template):
result.setdefault("compose_ex_foreign_key", result["compose_normal_attribute"])
result.setdefault("compose_primary_ex_foreign_key", result["compose_primary_key"])
result.setdefault("compose_association_attribute", result["compose_normal_attribute"])
result.setdefault("compose_association_primary_key", result["compose_primary_key"])
result.setdefault("compose_deleted_child_attribute", result["compose_normal_attribute"])
result.setdefault("compose_deleted_child_discriminator_", result["compose_normal_attribute"])
result.setdefault("compose_deleted_child_discriminator_T", result["compose_normal_attribute"])
Expand All @@ -53,6 +54,7 @@ def set_defaults(template):
result.setdefault("compose_deleted_parent_primary_key", result["compose_primary_key"])
result.setdefault("compose_stopped_foreign_key", result["compose_foreign_key"])
result.setdefault("compose_outer_attribute", result["compose_normal_attribute"])
result.setdefault("compose_outer_primary_key", result["compose_primary_key"])
result.setdefault("compose_parent_primary_key", result["compose_primary_foreign_key"])
result.setdefault("compose_strengthening_primary_foreign_key", result["compose_primary_foreign_key"])
result.setdefault("compose_strengthening_primary_ex_foreign_key", result["compose_primary_key"])
Expand Down Expand Up @@ -476,14 +478,14 @@ def process_associations(self):
})
self.relations[association.bid]["columns"].extend({ # and the attributes already existing in the association
"attribute": attribute.label,
"optionality": self.pop_optionality_from_datatype(attribute),
"optionality": "!" if attribute.kind == "strong" else self.pop_optionality_from_datatype(attribute),
"datatype": attribute.datatype,
"adjacent_source": None,
"outer_source": None,
"association_name": association.name_view,
"leg_note": None,
"is_primary": False,
"nature": "association_attribute",
"is_primary": attribute.kind == "strong",
"nature": "association_primary_key" if attribute.kind == "strong" else "association_attribute",
"unicities": "",
} for attribute in association.attributes if attribute.label.strip() != ""
)
Expand Down Expand Up @@ -575,14 +577,14 @@ def process_associations(self):
# Add the attributes already existing in the association
self.relations[df_leg.entity_bid]["columns"].extend([{
"attribute": attribute.label,
"optionality": self.pop_optionality_from_datatype(attribute),
"optionality": "!" if attribute.kind == "strong" else self.pop_optionality_from_datatype(attribute),
"datatype": attribute.datatype,
"association_name": association.name_view,
"adjacent_source": None,
"outer_source": None,
"leg_note": None,
"is_primary": False,
"nature": "outer_attribute",
"is_primary": attribute.kind == "strong",
"nature": "outer_primary_key" if attribute.kind == "strong" else "outer_attribute",
"unicities": "",
} for attribute in association.attributes if attribute.label.strip() != ""])

Expand Down
4 changes: 2 additions & 2 deletions mocodo/parse_mcd.py

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion mocodo/resources/grammar.lark
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ comment: PERCENT /.*\r?\n/

// Associations

assoc_clause: box_def_prefix? assoc_name_def COMMA seq{assoc_leg} (COLON seq{typed_attr})? NL
assoc_clause: box_def_prefix? assoc_name_def COMMA seq{assoc_leg} (COLON seq{assoc_attr})? NL
assoc_name_def: box_name
assoc_leg: _assoc_card? leg_arrow? SP? (LBRACKET leg_note? RBRACKET)? entity_name_ref
_assoc_card: card_hidden? card_prefix? card
Expand All @@ -52,6 +52,7 @@ entity_name_ref: box_name
CARD.2: /(?![-_\/])(\w|\?){2}(?=[ \t]*[^\w,\r\n:])/
LEG_ARROW: /[<>]/
leg_note: note
assoc_attr: id_mark? typed_attr

// Entities

Expand Down
Binary file modified mocodo/resources/i18n/messages_fr.mo
Binary file not shown.
8 changes: 8 additions & 0 deletions mocodo/resources/i18n/messages_fr.po
Original file line number Diff line number Diff line change
Expand Up @@ -388,10 +388,18 @@ msgstr "applique à tous les textes calculés le facteur de mise à l'échelle d
msgid "raise an error when horizontal or vertical legs overlap"
msgstr "lève une erreur quand des pattes horizontales ou verticales se chevauchent"

#: mocodo/argument_parser.py:424
msgid "forbid the use of identifiers in associations (according to the Merise standard)"
msgstr "interdit l'utilisation d'identifiants dans les associations (conformément au standard Merise)"

#: mocodo/argument_parser.py:586
msgid "set the visibility and the contents of the lateral gutters"
msgstr "définit la visibilité et le contenu des gouttières latérales"

#: mocodo/association.py:40
msgid "The association \"{name}\" cannot have an identifier."
msgstr "L'association « {name} » ne peut pas avoir d'identifiant."

#: mocodo/association.py:50
msgid "The association \"{name}\" should have at least 3 legs to become a cluster."
msgstr "L'association « {name} » devrait avoir au moins 3 pattes pour devenir un agrégat."
Expand Down
2 changes: 2 additions & 0 deletions mocodo/resources/relation_templates/html-c.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ transform_relation_name:
search: '<'
replace: '&lt;'
compose_association_attribute: '<span class=''normal''>{label}</span>'
compose_association_primary_key: '<span class=''primary''>{label}</span>'
compose_deleted_child_attribute: '<span class=''normal''>{label}</span>'
compose_deleted_child_discriminator_: '<span class=''normal''>{label}</span>'
compose_deleted_child_discriminator_T: '<span class=''normal''>{label}</span>'
Expand All @@ -43,6 +44,7 @@ compose_foreign_key: '<span class=''foreign''>#{label}</span>'
compose_ex_foreign_key: '<span class=''normal''>{label}</span>'
compose_normal_attribute: '<span class=''normal''>{label}</span>'
compose_outer_attribute: '<span class=''normal''>{label}</span>'
compose_outer_primary_key: '<span class=''primary''>{label}</span>'
compose_parent_primary_key: '<span class=''foreign primary''>#{label}</span>'
compose_primary_foreign_key: '<span class=''foreign primary''>#{label}</span>'
compose_primary_key: '<span class=''primary''>{label}</span>'
Expand Down
10 changes: 6 additions & 4 deletions mocodo/resources/relation_templates/html-ce.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
parent: 'html-c'
compose_association_attribute: '<span class=''normal''>{label}</span><item>Le champ <i>{label}</i> était déjà un simple attribut de l''association <i>{this_relation_name}</i>.</item>'
compose_association_primary_key: '<span class=''primary''>{label}</span><item>Le champ <i>{label}</i> fait partie de la clé primaire de la table<primary></primary>. C''était déjà un « identifiant » de l''association <i>{this_relation_name}</i>. <strong>Attention</strong> : la notion d''identifiant d''association n''existe pas en Merise ; il s''agit d''une commodité introduite par Mocodo pour éviter d''inclure dans l''association une entité réduite à cet identifiant.</item>'
compose_deleted_child_attribute: '<span class=''normal''>{label}</span><item>Le champ <i>{label}</i> a migré à partir de l''entité-fille <i>{adjacent_source}</i> (supprimée).</item>'
compose_deleted_child_discriminator_: '<span class=''normal''>{label}</span><item>Un discriminateur <i>{label}</i> est ajouté pour indiquer la nature de la spécialisation. Peut être vide, du fait de l''absence de contrainte de totalité.</item>'
compose_deleted_child_discriminator_T: '<span class=''normal''>{label}</span><item>Un discriminateur <i>{label}</i> est ajouté pour indiquer la nature de la spécialisation. Jamais vide, du fait de la contrainte de totalité.</item>'
Expand All @@ -20,6 +21,7 @@ compose_foreign_key: '<span class=''foreign''>#{label}</span><item>Le champ <i>{
compose_ex_foreign_key: '<span class=''normal''>{label}</span><item>Le champ <i>{label}</i> est un simple attribut. Il a migré par l''association de dépendance fonctionnelle <i>{association_name}</i> à partir de l''entité <i>{outer_source}</i> en perdant son caractère identifiant. Cependant, comme la table créée à partir de cette entité a été supprimée, il n''est pas considéré comme clé étrangère.</item>'
compose_normal_attribute: '<span class=''normal''>{label}</span><item>Le champ <i>{label}</i> était déjà un simple attribut de l''entité <i>{this_relation_name}</i>.</item>'
compose_outer_attribute: '<span class=''normal''>{label}</span><item>Le champ <i>{label}</i> a migré à partir de l''association de dépendance fonctionnelle <i>{association_name}</i>.</item>'
compose_outer_primary_key: '<span class=''primary''>{label}</span><item>Le champ <i>{label}</i> fait partie de la clé primaire de la table<primary></primary>. Il a migré à partir de l''association de dépendance fonctionnelle <i>{association_name}</i> dont il était « identifiant ». <strong>Attention</strong> : la notion d''identifiant d''association n''existe pas en Merise ; il s''agit d''une tolérance introduite par Mocodo, mais vous devriez vraisemblablement placer cet identifiant dans l''entité <primary></primary>.</item>'
compose_parent_primary_key: '<span class=''foreign primary''>#{label}</span><item>Le champ <i>{label}</i> fait partie de la clé primaire de la table<primary></primary>. C''est une clé étrangère qui a migré à partir de l''entité-mère <i>{outer_source}</i>.</item>'
compose_primary_foreign_key: '<span class=''foreign primary''>#{label}</span><item>Le champ <i>{label}</i> fait partie de la clé primaire de la table<primary></primary>. C''est une clé étrangère qui a migré directement à partir de l''entité <i>{outer_source}</i>.</item>'
compose_primary_key: '<span class=''primary''>{label}</span><item>Le champ <i>{label}</i> fait partie de la clé primaire de la table<primary></primary>. C''était déjà un identifiant de l''entité <i>{this_relation_name}</i>.</item>'
Expand All @@ -28,10 +30,10 @@ compose_stopped_foreign_key: '<span class=''foreign''>#{label}</span><item>Le ch
compose_stopped_ex_foreign_key: '<span class=''normal''>{label}</span><item>Le champ <i>{label}</i> est un simple attribut. Il a migré directement à partir de l''entité <i>{outer_source}</i> en perdant son caractère identifiant. Cependant, comme la table créée à partir de cette entité a été supprimée, il n''est pas considéré comme clé étrangère.</item>'
compose_strengthening_primary_foreign_key: '<span class=''foreign primary''>#{label}</span><item>Le champ <i>{label}</i> fait partie de la clé primaire de la table<primary></primary>. C''est une clé étrangère qui a migré à partir de l''entité <i>{outer_source}</i> pour renforcer l''identifiant.</item>'
compose_strengthening_primary_ex_foreign_key: '<span class=''primary''>{label}</span><item>Le champ <i>{label}</i> fait partie de la clé primaire de la table<primary></primary>. Il a migré à partir de l''entité <i>{outer_source}</i> pour renforcer l''identifiant. Cependant, comme la table créée à partir de cette entité a été supprimée, il n''est pas considéré comme clé étrangère.</item>'
compose_unsourced_foreign_key: '<span class=''normal''>{label}</span><item>Le champ <i>{label}</i> a migré par l''association de dépendance fonctionnelle <i>{association_name}</i> à partir de l''entité <i>{adjacent_source}</i> (supprimée). **Attention**\xa0: aucune contrainte d''intégrité référentielle n''est plus assurée.</item>'
compose_unsourced_ex_foreign_key: '<span class=''normal''>{label}</span><item>Le champ <i>{label}</i> a migré par l''association de dépendance fonctionnelle <i>{association_name}</i> à partir de l''entité <i>{adjacent_source}</i> (supprimée). **Attention**\xa0: aucune contrainte d''intégrité référentielle n''est plus assurée.</item>'
compose_unsourced_primary_foreign_key: '<span class=''primary''>{label}</span><item>Le champ <i>{label}</i> fait partie de la clé primaire de la table<primary></primary>. Il a migré par l''association de dépendance fonctionnelle <i>{association_name}</i> à partir de l''entité <i>{adjacent_source}</i> (supprimée). **Attention**\xa0: aucune contrainte d''intégrité référentielle n''est plus assurée.</item>'
compose_unsourced_primary_ex_foreign_key: '<span class=''primary''>{label}</span><item>Le champ <i>{label}</i> fait partie de la clé primaire de la table<primary></primary>. Il a migré par l''association de dépendance fonctionnelle <i>{association_name}</i> à partir de l''entité <i>{adjacent_source}</i> (supprimée). **Attention**\xa0: aucune contrainte d''intégrité référentielle n''est plus assurée.</item>'
compose_unsourced_foreign_key: '<span class=''normal''>{label}</span><item>Le champ <i>{label}</i> a migré par l''association de dépendance fonctionnelle <i>{association_name}</i> à partir de l''entité <i>{adjacent_source}</i> (supprimée). <strong>Attention</strong> : aucune contrainte d''intégrité référentielle n''est plus assurée.</item>'
compose_unsourced_ex_foreign_key: '<span class=''normal''>{label}</span><item>Le champ <i>{label}</i> a migré par l''association de dépendance fonctionnelle <i>{association_name}</i> à partir de l''entité <i>{adjacent_source}</i> (supprimée). <strong>Attention</strong> : aucune contrainte d''intégrité référentielle n''est plus assurée.</item>'
compose_unsourced_primary_foreign_key: '<span class=''primary''>{label}</span><item>Le champ <i>{label}</i> fait partie de la clé primaire de la table<primary></primary>. Il a migré par l''association de dépendance fonctionnelle <i>{association_name}</i> à partir de l''entité <i>{adjacent_source}</i> (supprimée). <strong>Attention</strong> : aucune contrainte d''intégrité référentielle n''est plus assurée.</item>'
compose_unsourced_primary_ex_foreign_key: '<span class=''primary''>{label}</span><item>Le champ <i>{label}</i> fait partie de la clé primaire de la table<primary></primary>. Il a migré par l''association de dépendance fonctionnelle <i>{association_name}</i> à partir de l''entité <i>{adjacent_source}</i> (supprimée). <strong>Attention</strong> : aucune contrainte d''intégrité référentielle n''est plus assurée.</item>'
compose_relation: '<div>\n <details><summary><span class=''relation''>{this_relation_name}</span> (\n {columns}\n )</summary>\n</div>'
compose_deleted_relation: 'La table <i>{this_relation_name}</i> a été supprimée car elle était réduite à la clé primaire de son entité d''origine. Pour conserver de telles tables, préfixez d''un « + » la définition des entités d''origine.'
add_unicity_constraints:
Expand Down
7 changes: 6 additions & 1 deletion mocodo/tools/parser_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def parse_source(source):
raise MocodoError(519, _('{pin}The constraint targets must be comma-separated.').format(pin=pin)) # fmt: skip
if expected == {'HASHTAG', 'NL', 'ID_GROUPS', 'ID_MARK', 'ATTR', 'COMMA'}:
raise MocodoError(500, _('{pin}An attribute label cannot start with "{v[1]!r}".').format(pin=pin, v=v)) # fmt: skip
if expected == {'NL', 'ATTR', 'COMMA'}:
if expected == {'ID_MARK', 'NL', 'ATTR', 'COMMA'}:
raise MocodoError(500, _('{pin}An attribute label cannot start with "{v[1]!r}".').format(pin=pin, v=v)) # fmt: skip
if expected == {'LBRACKET', 'NL', 'COMMA'}:
raise MocodoError(521, _('{pin}An attribute label cannot contain "{v}".').format(pin=pin, v=v)) # fmt: skip
Expand Down Expand Up @@ -207,6 +207,11 @@ def seq(self, tree):
items.append(d)
return (f"{tree[0][0]}s", items)

def assoc_attr(self, tree):
if tree[0] == "_":
tree[-1][1]["id_mark"] = "_"
return ("attr", tree[-1][1])

def assoc_leg(self, tree):
return ("leg", dict(tree))

Expand Down
2 changes: 1 addition & 1 deletion mocodo/version_number.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
version = "4.1.0"
version = "4.1.1"
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "mocodo"
version = "4.1.0"
version = "4.1.1"
description = "Modélisation Conceptuelle de Données. Nickel. Ni souris."
authors = ["Aristide Grange"]
license = "MIT"
Expand Down
5 changes: 5 additions & 0 deletions test/test_association.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ def test_attributes(self):
self.assertEqual([att.label for att in a.attributes], ["note stage", "heure soutenance"])
self.assertEqual([att.__class__ for att in a.attributes], [SimpleAssociationAttribute, SimpleAssociationAttribute])

def test_identifiers(self):
a = association_wrapper("Réserver, 1N Client, 0N Chambre: _Date, Durée")
self.assertEqual([att.label for att in a.attributes], ["Date", "Durée"])
self.assertEqual([att.__class__ for att in a.attributes], [StrongAttribute, SimpleAssociationAttribute])

def test_other_card(self):
a = association_wrapper("SOUTENIR, XX ÉTUDIANT, XX DATE: note stage")
self.assertTrue(not a.legs[0].card_view.strip())
Expand Down
1 change: 1 addition & 0 deletions test/test_parser_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@
Étudiant: 0_num, 1_nom, 1_prénom, adresse, 2_mail
Position: 0_latitude, 0_longitude, altitude
Foo: bar, 1_baz, 21_qux, 123_quux
Réserver, 1N Client, 0N Chambre: _date, durée
""".splitlines()

line = "-" * 80
Expand Down
Loading

0 comments on commit cbdcc08

Please sign in to comment.