Skip to content

Commit

Permalink
Uppercase org/group/status. Fold type/groupTypes into the general Gro…
Browse files Browse the repository at this point in the history
…up/Status classes; kill GroupW3C/StatusW3C.
  • Loading branch information
tabatkins committed Aug 20, 2024
1 parent ba5aad6 commit 8035e8b
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 91 deletions.
4 changes: 2 additions & 2 deletions bikeshed/boilerplate.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def getFillContainer(tag: str, doc: t.SpecT, default: bool = False) -> t.Element

# Otherwise, append to the end of the document,
# unless you're in the byos group
if doc.doctype.group.name == "byos":
if doc.doctype.group.name == "BYOS":
return None
if default:
return doc.body
Expand Down Expand Up @@ -240,7 +240,7 @@ def removeUnwantedBoilerplate(doc: t.SpecT) -> None:


def w3cStylesheetInUse(doc: t.SpecT) -> bool:
return doc.md.prepTR or doc.doctype.group.name == "w3c"
return doc.md.prepTR or doc.doctype.group.name == "W3C"


def addBikeshedBoilerplate(doc: t.SpecT) -> None:
Expand Down
2 changes: 1 addition & 1 deletion bikeshed/doctypes/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from .manager import NIL_GROUP, NIL_ORG, NIL_STATUS, DoctypeManager, Group, GroupW3C, Org, Status, StatusW3C
from .manager import NIL_GROUP, NIL_ORG, NIL_STATUS, DoctypeManager, Group, Org, Status
64 changes: 17 additions & 47 deletions bikeshed/doctypes/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class Doctype:
group: Group
status: Status

def __str__(self):
def __str__(self) -> str:
return f"Doctype<org={self.org.name}, group={self.group.fullName()}, status={self.status.fullName()}>"


Expand Down Expand Up @@ -97,7 +97,7 @@ class Org:

@staticmethod
def fromKdlNode(node: kdl.Node) -> Org:
name = t.cast(str, node.args[0])
name = t.cast(str, node.args[0]).upper()
self = Org(name)
for child in node.getAll("group"):
g = Group.fromKdlNode(child, org=self)
Expand All @@ -120,6 +120,7 @@ class Group:
privSec: bool
org: Org
requires: list[str] = dataclasses.field(default_factory=list)
type: str | None = None

def fullName(self) -> str:
if self.org:
Expand All @@ -129,14 +130,15 @@ def fullName(self) -> str:

@staticmethod
def fromKdlNode(node: kdl.Node, org: Org) -> Group:
if org.name == "w3c":
return GroupW3C.fromKdlNode(node, org)
name = t.cast(str, node.args[0])
name = t.cast(str, node.args[0]).upper()
privSec = t.cast(bool, node.props.get("priv-sec", False))
requiresNode = node.get("requires")
self = Group(name, privSec, org)
if requiresNode:
self.requires = t.cast("list[str]", list(requiresNode.getArgs((..., str))))
if "type" in node.props:
groupType = str(node.props.get("type")).lower()
else:
groupType = None
self = Group(name, privSec, org, type=groupType)
for n in node.getAll("requires"):
self.requires.extend(t.cast("list[str]", n.getArgs((..., str))))
return self

def __bool__(self) -> bool:
Expand All @@ -146,24 +148,13 @@ def __bool__(self) -> bool:
NIL_GROUP = Group("(not provided)", privSec=False, org=NIL_ORG)


@dataclasses.dataclass
class GroupW3C(Group):
type: str | None = None

@staticmethod
def fromKdlNode(node: kdl.Node, org: Org) -> GroupW3C:
name = t.cast(str, node.args[0])
privSec = t.cast(bool, node.props.get("priv-sec", False))
groupType = t.cast("str|None", node.props.get("type"))
return GroupW3C(name, privSec, org, [], groupType)


@dataclasses.dataclass
class Status:
name: str
longName: str
org: Org
requires: list[str] = dataclasses.field(default_factory=list)
groupTypes: list[str] = dataclasses.field(default_factory=list)

def fullName(self) -> str:
if self.org:
Expand All @@ -183,38 +174,17 @@ def looselyMatch(self, rawStatus: str) -> bool:
def fromKdlNode(node: kdl.Node, org: Org | None = None) -> Status:
if org is None:
org = NIL_ORG
if org and org.name == "w3c":
return StatusW3C.fromKdlNode(node, org)
name = t.cast(str, node.args[0])
name = t.cast(str, node.args[0]).upper()
longName = t.cast(str, node.args[1])
self = Status(name, longName, org)
requiresNode = node.get("requires")
if requiresNode:
self.requires = t.cast("list[str]", list(requiresNode.getArgs((..., str))))
for n in node.getAll("requires"):
self.requires.extend(t.cast("list[str]", n.getArgs((..., str))))
for n in node.getAll("group-types"):
self.groupTypes.extend(str(x).lower() for x in n.getArgs((..., str)))
return self

def __bool__(self) -> bool:
return self != NIL_STATUS


NIL_STATUS = Status("(not provided)", "", org=NIL_ORG)


@dataclasses.dataclass
class StatusW3C(Status):
groupTypes: list[str] = dataclasses.field(default_factory=list)

@staticmethod
def fromKdlNode(node: kdl.Node, org: Org | None = None) -> StatusW3C:
if org is None:
org = NIL_ORG
name = t.cast(str, node.args[0])
longName = t.cast(str, node.args[1])
self = StatusW3C(name, longName, org)
requiresNode = node.get("requires")
if requiresNode:
self.requires = t.cast("list[str]", list(requiresNode.getArgs((..., str))))
groupTypesNode = node.get("group-types")
if groupTypesNode:
self.groupTypes = t.cast("list[str]", list(groupTypesNode.getArgs((..., str))))
return self
56 changes: 23 additions & 33 deletions bikeshed/doctypes/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from .. import messages as m

if t.TYPE_CHECKING:
from . import DoctypeManager, Group, GroupW3C, Org, Status, StatusW3C # pylint: disable=cyclic-import
from . import DoctypeManager, Group, Org, Status # pylint: disable=cyclic-import


def canonicalize(
Expand All @@ -20,10 +20,12 @@ def canonicalize(
# any inline org specifiers.
# Then, figure out what the actual org name is.
orgFromStatus, statusName = splitOrg(rawStatus)
orgFromStatus = orgFromStatus.upper() if orgFromStatus is not None else None
statusName = statusName.upper() if statusName is not None else None

orgFromGroup, groupName = splitOrg(rawGroup)
groupName = groupName.lower() if groupName is not None else None
orgFromGroup = orgFromGroup.upper() if orgFromGroup is not None else None
groupName = groupName.upper() if groupName is not None else None

orgName = reconcileOrgs(rawOrg, orgFromStatus, orgFromGroup)

Expand Down Expand Up @@ -95,12 +97,23 @@ def canonicalize(
if group and status and status.org and status.org != group.org:
# If using an org-specific Status, Group must match.
# (Any group can use a generic status.)
possibleStatusNames = config.englishFromList(f"'{x}'" for x in group.org.statuses)
possibleStatusNames = [x.name for x in group.org.statuses.values()]
m.die(
f"Your Group is in the '{group.org.name}' Org, but your Status is only usable in the '{status.org.name}' Org. Allowed Status values for '{group.org.name}' are: {possibleStatusNames}",
f"Your Group ({group.name}) is in the '{group.org.name}' Org, but your Status ({status.name}) is only usable in the '{status.org.name}' Org. Allowed Status values for '{group.org.name}' are {config.englishFromList(sorted(possibleStatusNames))}",
)

if group and status and group.org.name == "w3c":
if group and group.type is not None and status and status.groupTypes and group.type not in status.groupTypes:
allowedStatuses = [s.name for s in group.org.statuses.values() if group.type in s.groupTypes]
if allowedStatuses:
m.warn(
f"You used Status {status.name}, but your Group ({group.name}) is limited to the statuses {config.englishFromList(sorted(allowedStatuses))}.",
)
else:
m.die(
f"PROGRAMMING ERROR: Group '{group.fullName()}' has type '{group.type}', but none of the {group.org.name} Statuses are associated with that type.",
)

if group and status and group.org.name == "W3C":
# Apply the special w3c rules
validateW3CStatus(group, status)

Expand Down Expand Up @@ -158,9 +171,9 @@ def reconcileOrgs(fromRaw: str | None, fromStatus: str | None, fromGroup: str |
# Since there are three potential sources of "org" name,
# figure out what the name actually is,
# and complain if they disagree.
fromRaw = fromRaw.lower() if fromRaw else None
fromStatus = fromStatus.lower() if fromStatus else None
fromGroup = fromGroup.lower() if fromGroup else None
fromRaw = fromRaw.upper() if fromRaw else None
fromStatus = fromStatus.upper() if fromStatus else None
fromGroup = fromGroup.upper() if fromGroup else None

orgName: str | None = fromRaw

Expand Down Expand Up @@ -188,35 +201,12 @@ def reconcileOrgs(fromRaw: str | None, fromStatus: str | None, fromGroup: str |


def validateW3CStatus(group: Group, status: Status) -> None:
if t.TYPE_CHECKING:
assert isinstance(group, GroupW3C)
assert isinstance(status, StatusW3C)
if status.org is None and status.name == "DREAM":
if status.name == "DREAM":
m.warn("You used Status:DREAM for a W3C document. Consider Status:UD instead.")

if status.name in ("IG-NOTE", "WG-NOTE"):
m.die(
f"Under Process2021, {status.name} is no longer a valid status. Use NOTE (or one of its variants NOTE-ED, NOTE-FPWD, NOTE-WD) instead.",
)

if group.type is not None and group.type not in status.groupTypes:
if group.type == "ig":
longTypeName = "W3C Interest Groups"
elif group.type == "tag":
longTypeName = "the W3C TAG"
elif group.type == "cg":
longTypeName = "W3C Community/Business Groups"
else:
longTypeName = "W3C Working Groups"
allowedStatuses = [
x for x in t.cast("list[StatusW3C]", group.org.statuses.values()) if group.type in x.groupTypes
]
if allowedStatuses:
m.warn(
f"You used Status:{status.name}, but {longTypeName} are limited to these statuses: {allowedStatuses}.",
)
else:
m.die(
f"PROGRAMMING ERROR: Group '{group.fullName()}' has type '{group.type}', but that isn't present in any of org's Statuses.",
)
return

10 changes: 5 additions & 5 deletions bikeshed/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ def computeImplicitMetadata(self, doc: t.SpecT) -> None:
# Do some "computed metadata", based on the value of other metadata.
# Only call this when you're sure all metadata sources are parsed.

if doc.doctype.group.name == "byos":
if doc.doctype.group.name == "BYOS":
self.boilerplate.default = False
if not self.repository and doc:
self.repository = getSpecRepository(doc)
Expand All @@ -213,7 +213,7 @@ def computeImplicitMetadata(self, doc: t.SpecT) -> None:
m.state.dieOn = self.dieOn

def validate(self, doc: t.SpecT) -> bool:
if doc.doctype.group.name == "byos":
if doc.doctype.group.name == "BYOS":
return True

if not self.hasMetadata:
Expand Down Expand Up @@ -285,7 +285,7 @@ def fillTextMacros(self, macros: t.DefaultDict[str, str], doc: t.SpecT) -> None:
macros["longstatus"] = doc.doctype.status.longName
else:
macros["longstatus"] = ""
if doc.doctype.group.name == "w3c":
if doc.doctype.group.name == "W3C":
if doc.doctype.status.name in ("LCWD", "FPWD"):
macros["status"] = "WD"
elif doc.doctype.status.name in ("NOTE-FPWD", "NOTE-WD"):
Expand Down Expand Up @@ -328,7 +328,7 @@ def fillTextMacros(self, macros: t.DefaultDict[str, str], doc: t.SpecT) -> None:
if self.deadline:
macros["deadline"] = self.deadline.strftime(f"{self.deadline.day} %B %Y")
macros["isodeadline"] = self.deadline.strftime("%Y-%m-%d")
if doc.doctype.org.name == "w3c" and "Date" in doc.doctype.status.requires:
if doc.doctype.org.name == "W3C" and "Date" in doc.doctype.status.requires:
macros["version"] = (
f"https://www.w3.org/TR/{macros['year']}/{doc.doctype.status.name}-{macros['vshortname']}-{macros['cdate']}/"
)
Expand All @@ -350,7 +350,7 @@ def fillTextMacros(self, macros: t.DefaultDict[str, str], doc: t.SpecT) -> None:
macros["mailinglist"] = self.mailingList
if self.mailingListArchives:
macros["mailinglistarchives"] = self.mailingListArchives
if doc.doctype.org.name == "w3c":
if doc.doctype.org.name == "W3C":
statusName = doc.doctype.status.name
if statusName == "FPWD":
macros["w3c-stylesheet-url"] = "https://www.w3.org/StyleSheets/TR/2021/W3C-WD"
Expand Down
6 changes: 3 additions & 3 deletions bikeshed/retrieve.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,13 @@ def retrieveBoilerplateFile(

if group is None:
group = doc.doctype.group
groupName = group.name if group else None
groupName = group.name.lower() if group else None
if status is None:
status = doc.doctype.status
statusName = status.name if status else None
statusName = status.name.upper() if status else None
if org is None:
org = doc.doctype.org
orgName = org.name if org else None
orgName = org.name.lower() if org else None

searchLocally = allowLocal and doc.md.localBoilerplate[name]

Expand Down

0 comments on commit 8035e8b

Please sign in to comment.