tmp working changes from laptop

This commit is contained in:
Tim Van Baak 2022-12-12 17:30:10 -08:00
parent 2bd75328a1
commit 2fd92ca0b8
2 changed files with 164 additions and 16 deletions

View File

@ -0,0 +1,131 @@
"""
Submodule for citation logic.
"""
import enum
from typing import Sequence, Set, List, Dict, Union
from amanuensis.backend import *
from amanuensis.db import Lexicon, Article
from amanuensis.parser import *
class CitationNodeType(enum.Enum):
ExtantWritten = 0
"""Title of an article that was previously written."""
ExtantPhantom = 1
"""Unwritten title cited by an extant written article."""
NewDraft = 2
"""Title of a pending article with a new title."""
PhantomDraft = 3
"""Title of a pending article with a phantom title."""
PhantomPending = 4
"""Unwritten title cited by a draft article."""
class CitationNode:
"""
Represents an article in the context of citations. Phantom articles do not
correspond to articles in the database.
"""
def __init__(self, title: str, node_type: CitationNodeType) -> None:
self.title: str = title
self.cites: Set[CitationNode] = set()
self.cited_by: Set[CitationNode] = set()
self.node_type: CitationNodeType = node_type
class CitationMap:
"""Represents metadata about which articles cite each other."""
def __init__(self) -> None:
self.by_title: Dict[str, CitationNode] = {}
def __contains__(self, title: str) -> bool:
return title in self.by_title
def __getitem__(self, title: str) -> CitationNode:
return self.by_title[title]
def get_or_add(self, title: str, node_type: CitationNodeType) -> CitationNode:
"""
Get the citation node for a title. If one does not exist, create it
with the given type.
"""
if title not in self.by_title:
self.add(title, node_type)
return self.by_title[title]
def add(self, title: str, node_type: CitationNodeType) -> None:
"""
Create a citation node with the given title and type.
"""
self.by_title[title] = CitationNode(title, node_type)
def create_citation(
self, citer: Union[CitationNode, str], cited: Union[CitationNode, str]
) -> None:
"""Add a citation between two titles."""
if isinstance(citer, str):
citer = self.by_title[citer]
if isinstance(cited, str):
cited = self.by_title[cited]
citer.cites.add(cited)
cited.cited_by.add(citer)
class GetCitations(RenderableVisitor):
"""Returns a list of all article titles cited in this article."""
def __init__(self) -> None:
self.citations: List[str] = []
def CitationSpan(self, span):
self.citations.append(span.cite_target)
def ParsedArticle(self, span):
return self.citations
def create_citation_map(lexicon: Lexicon, articles: Sequence[Article]) -> CitationMap:
"""
Generates mappings useful for tracking citations.
"""
article: Article
citemap = CitationMap()
# Add extant articles to the citation map
for article in articles:
if article.turn < lexicon.current_turn:
citemap.add(article.title, CitationNodeType.ExtantWritten)
# Add phantoms created by extant articles
for article in articles:
if article.turn < lexicon.current_turn:
parsed = parse_raw_markdown(article.body)
citeds = parsed.render(GetCitations())
for cited in citeds:
cited_node = citemap.get_or_add(cited, CitationNodeType.ExtantPhantom)
citemap.create_citation(article.title, cited_node)
# Add drafts, noting new and phantom drafts
for article in articles:
if article.turn >= lexicon.current_turn:
draft_node = citemap.get_or_add(article.title, CitationNodeType.NewDraft)
if draft_node.node_type == CitationNodeType.ExtantPhantom:
draft_node.node_type = CitationNodeType.PhantomDraft
# Add phantoms created by drafts
for article in articles:
if article.turn >= lexicon.current_turn:
parsed = parse_raw_markdown(article.body)
citeds = parsed.render(GetCitations())
for cited in citeds:
cited_node = citemap.get_or_add(cited, CitationNodeType.PhantomPending)
citemap.create_citation(article.title, cited_node)
return citemap

View File

@ -4,15 +4,18 @@ from typing import Sequence
from amanuensis.db import *
from amanuensis.parser import *
from .citation import CitationMap, CitationNodeType, create_citation_map
class ConstraintCheck(RenderableVisitor):
"""Analyzes an article for content-based constraint violations."""
def __init__(self) -> None:
self.word_count: int = 0
self.signatures: int = 0
def TextSpan(self, span):
self.word_count += len(re.split(r'\s+', span.innertext.strip()))
self.word_count += len(re.split(r"\s+", span.innertext.strip()))
return self
def SignatureParagraph(self, span):
@ -50,24 +53,44 @@ class ConstraintMessage:
return {"severity": self.severity, "message": self.message}
def title_constraint_check(title: str) -> Sequence[ConstraintMessage]:
"""Perform checks that apply to the article title."""
def constraint_check(
article: Article,
parsed: Renderable,
citemap: CitationMap,
) -> Sequence[ConstraintMessage]:
""""""
messages = []
# TODO: Need
# player index assignments for article turn
# extant article titles
# pending article titles
# phantom article titles
# pending phantom article titles
# index capacities
title = article.title
# author_id = article.character_id
###
# Constraints that apply to the title
###
# I: Current index assignments
# TODO
# E: No title
if not title:
if not article.title:
messages.append(ConstraintMessage.error("Missing title"))
# I: This article is new
# TODO
# E: And new articles are forbidden
# TODO
if citemap[title].node_type == CitationNodeType.NewDraft:
# I: This article is new
messages.append(ConstraintMessage.info("Writing a new article"))
# I: This article is a phantom
# TODO
# E: New articles are forbidden
# TODO
if citemap[title].node_type == CitationNodeType.PhantomDraft:
# I: This article is a phantom
messages.append(ConstraintMessage.info("Writing a phantom article")
# I: This article is an addendum
# TODO
@ -98,14 +121,8 @@ def title_constraint_check(title: str) -> Sequence[ConstraintMessage]:
# W: The article's title matches a character's name
# TODO
return messages
def content_constraint_check(parsed: Renderable) -> Sequence[ConstraintMessage]:
check_result: ConstraintCheck = parsed.render(ConstraintCheck())
messages = []
# I: Word count
messages.append(ConstraintMessage.info(f"Word count: {check_result.word_count}"))