Requirements
Requirements management records what a system must, should or may do, who wrote and owns each requirement, how it evolved, and how the requirements of different engineering disciplines relate to each other: an electrical requirement has its counterpart in the FPGA firmware, and this one in the software.
Data Model
The requirements model of pyEDAA.Reports.Requirements is built from typed values: no file format is read yet.
Every element carries key-value pairs for the information the model has no field for (element["effort"] = 3).
The
RequirementSpecificationregisters every person by user ID, and every persona, label, document and layer, every requirement and every specification item - also the child items - by its ID. An ID is unique among the elements of a class; a duplicate raises the duplicate error of its class, e.g.DuplicateRequirementError- each aDuplicateElementErrorand aRequirementsError. Each registry is a dictionary property, e.g.Labels, with an iterator taking an optional predicate, e.g.IterateLabels().The root’s
Versionis the version of the specification itself; its name is optional.A
Personais a role a user of the system acts in, e.g. an administrator, a reviewer or a quality inspector. A real person is aPersonwith a user ID, a name and an optional e-mail address. A person has no parent:AddPerson()registers it, and the same person may be registered in several specifications.Every element knows the element containing it -
Parent- and its specification -Root. Assigning a parent, in the constructor or later, adds the element to it and passes the specification on to the elements below it. An element, which already has a parent, raises anAlreadyInSpecificationError- anAlreadyInHierarchyError.An item refers only to personas, labels, documents and layers of its own specification. An element or person of another specification raises a
NotInSameSpecificationError- aNotInSameHierarchyError: it is valid, but not part of the specification.
Requirements
A Requirement has an ID, a title, a description, a creation time - the current time, unless given - and a
RequirementKind, which names what it constrains: e.g. a function, its performance, a quality, safety or
security, an interface, the environment, a design constraint or a regulation. Its Obligation answers whether
it is mandatory or optional, by the levels of ISO/IEC/IEEE 29148 and RFC 2119:
Obligation |
Keyword |
Meaning |
|---|---|---|
|
shall, must |
Binding; the default. |
|
should |
A goal; a deviation is justified. |
|
may |
A permission. |
Its ItemState follows its life cycle from Placeholder over Draft, InReview, Final and
Implemented to Verified; a new requirement is a Draft. A verified requirement is Closed, when it is
released and changes no more, e.g. in a baseline. At any time, a requirement can be Rejected or become
Obsolete.
A requirement belongs to at most one Layer: the requirements of one engineering discipline, e.g. electrical,
mechanical, FPGA firmware or software. A layer partitions the requirements; a selection across layers - e.g. the
requirements of a product variant - is a Label, or a predicate.
A requirement contains child requirements, which refine it. IterateChildren() iterates the children,
IterateDescendants() the children and grandchildren, depth-first.
IterateRequirements() iterates every requirement of the specification. Each takes an
optional predicate to select the requirements:
from pyTooling.Versioning import SemanticVersion
from pyEDAA.Reports import Person
from pyEDAA.Reports.Requirements import Layer, Requirement, RequirementKind, RequirementSpecification
specification = RequirementSpecification(SemanticVersion(1, 0, 0), "Board")
alice = Person("alice", "Alice", "alice@example.com")
specification.AddPerson(alice)
electrical = Layer("el", "Electrical", parent=specification)
power = Requirement("EL-1", "Power supply", RequirementKind.Functional, layer=electrical, authors=[alice],
parent=specification)
Requirement("EL-1.1", "Core rail", RequirementKind.Performance, "0.9 V, 5 A.", layer=electrical, parent=power)
for requirement in specification.IterateRequirements(lambda r: r.Kind is RequirementKind.Performance):
print(f"{requirement.ID}: {requirement.Title}")
Specification Items
A SpecificationItem mirrors a requirement - with an ID, a title, a state, a layer, persons, personas, labels,
documents, child items, links and a history - and states how the system meets requirements, e.g. a design decision or an
interface description. Specification items and requirements are in an N:M relation:
SpecificationItem.Requirements lists the requirements an item specifies, Requirement.SpecificationItems
the items specifying a requirement. SpecificationItem.AddRequirement() maintains both sides.
IterateSpecificationItems() iterates every specification item, with an optional
predicate.
Links
A Link starts at an item - its source - and points to another item of the same specification, its
destination. A link is no element of the item hierarchy: it has no parent. The source lists it as an outbound link, the
destination as an inbound link. Its LinkKind names the relationship: source kind destination.
LinkTo() and LinkFrom() create an outbound or inbound link of an item, with the
parameters of the link’s constructor.
Link kind |
The source … |
|---|---|
|
states the destination in more detail, outside the item hierarchy. |
|
is derived from the destination, e.g. a firmware requirement from an electrical one. |
|
is the destination’s counterpart in another layer. |
|
can only be met, if the destination is met. |
|
can’t be met together with the destination. |
|
states the same as the destination. |
|
replaces the destination, which is obsolete. |
|
has any other relationship to the destination. |
A source has one link of a kind to a destination. IterateOutboundLinks() and
IterateInboundLinks() take an optional predicate, e.g. to follow the counterparts of a requirement
through the layers.
Verification and Traceability
An item states its Rationale: why a requirement exists, or why a design decision was taken. A
requirement names the VerificationMethod flags verifying it - the inspection, analysis, demonstration and test
of ISO/IEC/IEEE 29148, plus simulation and formal verification - and its acceptance criteria.
IterateTrace() follows the links of an item transitively, IterateInboundTrace() the
inbound links; each item is reached once, also in a cycle. A predicate selects the links followed, e.g. the
counterparts of an electrical requirement through the FPGA firmware into the software:
for item in electrical.IterateInboundTrace(lambda link: link.Kind is LinkKind.CounterpartOf):
print(f"{item.ID} ({item.Layer.Name}): {item.Title}")
History
An item’s History lists the events of its life cycle in chronological order: an event can’t be
earlier than the item’s creation or its last event; a time without a time zone is a local time. A
HistoryEvent has an EventKind - e.g. opened, modified, approved, split, merged, closed or
obsoleted -, a time, optionally the person causing it, and the other items involved: a split names the items a
requirement was split into, a merge the items it was merged with.