Skip to content

Commit cdaf4f7

Browse files
author
Steve Canny
committed
document initial analysis
1 parent 399ec0b commit cdaf4f7

2 files changed

Lines changed: 167 additions & 0 deletions

File tree

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
=================
2+
Design Narratives
3+
=================
4+
5+
Narrative explorations into design issues, serving initially as an aid to
6+
reasoning and later as a memorandum of the considerations undertaken during
7+
the design process.
8+
9+
10+
Semi-random bits
11+
----------------
12+
13+
*partname* is a marshaling/serialization concern.
14+
15+
*partname* (pack URI) is the addressing scheme for accessing serialized parts
16+
within the package. It has no direct relevance to the unmarshaled graph except
17+
for use in re-marshaling unmanaged parts or to avoid renaming parts when the
18+
load partname will do just fine.
19+
20+
What determines part to be constructed? Relationship type or content type?
21+
22+
*Working hypothesis*: Content type should be used to determine the type of
23+
part to be constructed during unmarshaling.
24+
25+
Content type is more granular than relationship type. For example, an image
26+
part can be any of several content types, e.g. jpg, gif, or png. Another
27+
example is RT.OFFICE_DOCUMENT. This can apply to any of CT.PRESENTATION,
28+
CT.DOCUMENT, or CT.SPREADSHEET and their variants.
29+
30+
However, I can't think of any examples of where a particular content type
31+
may be the target of more than one possible relationship type. That seems
32+
like a logical possibility though.
33+
34+
There are examples of where a relationship type (customXml for example) are
35+
used to refer to more than one part type (Additional Characteristics,
36+
Bibliography, and Custom XML parts in this case). In such a case I expect
37+
the unmarshaling and part selection would need to be delegated to the source
38+
part which presumably would contain enough information to resolve the
39+
ambiguity in its body XML. In that case, a BasePart could be constructed and
40+
let the source part create a specific subclass on |after_unmarshal|.
41+
42+
When properties of a mutable type (e.g. list) are returned, what is returned
43+
should be a copy or perhaps an immutable variant (e.g. tuple) so that
44+
client-side changes don't need to be accounted for in testing. If the return
45+
value really needs to be mutable and a snapshot won't do, it's probably time to
46+
make it a custom collection so the types of mutation that are allowed can be
47+
specified and tested.
48+
49+
In PackURI, the baseURI property does not include any trailing slash. This
50+
behavior is consistent with the values returned from ``posixpath.split()`` and
51+
is then in a form suitable for use in ``posixpath.join()``.
52+
53+
54+
Design Narrative -- Blob proxy
55+
==============================
56+
57+
Certain use cases would be better served if loading large binary parts such as
58+
images could be postponed or avoided. For example, if the use case is to
59+
retrieve full text from a presentation for indexing purposes, the resources
60+
and time consumed to load images into memory is wasted. It seems feasible to
61+
develop some sort of blob proxy to postpone the loading of these binary parts
62+
until such time as they are actually required, passing a proxy of some type to
63+
be used instead. If it were cleverly done, the client code wouldn't have to
64+
know, i.e. the proxy would be transparent.
65+
66+
The main challenge I see is how to gain an entry point to close the zip archive
67+
after all loading has been completed. If it were reopened and closed each time
68+
a part was loaded that would be pretty expensive (an early verion of
69+
python-pptx did exactly that for other reasons). Maybe that could be done when
70+
the presentation is garbage collected or something.
71+
72+
Another challenge is how to trigger the proxy to load itself. Maybe blob could
73+
be an object that has file semantics and the read method could lazy load.
74+
75+
Another idea was to be able to open the package in read-only mode. If the file
76+
doesn't need to be saved, the actual binary objects don't actually need to be
77+
accessed. Maybe this would be more like read-text-only mode or something.
78+
I don't know how we'd guarantee that no one was interested in the image
79+
binaries, even if they promised not to save.
80+
81+
I suppose there could be a "read binary parts" method somewhere that gets
82+
triggered the first time a binary part is accessed, as it would be during
83+
save(). That would address the zip close entry point challenge.
84+
85+
It does all sound a bit complicated for the sake of saving a few milliseconds,
86+
unless someone (like Google :) was dealing with really large scale.
87+
88+
89+
Design Narrative -- Custom Part Class mapping
90+
=============================================
91+
92+
::
93+
94+
pkg.register_part_classes(part_class_mapping)
95+
96+
part_class_mapping = {
97+
CT_SLIDE: _Slide,
98+
CT_PRESENTATION: _Presentation
99+
...
100+
}
101+
102+
103+
Design Narrative -- Model-side relationships
104+
============================================
105+
106+
Might it make sense to maintain XML of .rels stream throughout life-cycle?
107+
--------------------------------------------------------------------------
108+
109+
No. The primary rationale is that a partname is not a primary model-side
110+
entity; partnames are driven by the serialization concern, providing a method
111+
for addressing serialized parts. Partnames are not required to be up-to-date in
112+
the model until after the |before_marshal| call to the part returns. Even if
113+
all part names were kept up-to-date, it would be a leakage across concern
114+
boundaries to require a part to notify relationships of name changes; not to
115+
mention it would introduce additional complexity that has nothing to do with
116+
manipulation of the in-memory model.
117+
118+
**always up-to-date principle**
119+
120+
Model-side relationships are maintained as new parts are added or existing
121+
parts are deleted. Relationships for generic parts are maintained from load
122+
and delivered back for save without change.
123+
124+
I'm not completely sure that the always-up-to-date principle need necessarily
125+
apply in every case. As long as the relationships are up-to-date before
126+
returning from the |before_marshal| call, I don't see a reason why that
127+
choice couldn't be at the designer's discretion. Because relationships don't
128+
have a compelling model-side runtime purpose, it might simplify the code to
129+
localize the pre-serialization concern to the |before_marshal| method.
130+
131+
.. |before_marshal| replace:: :meth:`before_marshal`
132+
.. |after_unmarshal| replace:: :meth:`after_unmarshal`
133+
134+
135+
Members
136+
-------
137+
138+
**rId**
139+
140+
The relationship identifier. Must be a unique xsd:ID string. It is usually
141+
of the form 'rId%d' % {sequential_int}, e.g. ``'rId9'``, but this need not
142+
be the case. In situations where a relationship is created (e.g. for a new
143+
part) or can be rewritten, e.g. if presentation->slide relationships were
144+
rewritten on |before_marshal|, this form is preferred. In all other cases
145+
the existing rId value should be preserved. When a relationship is what the
146+
spec terms as *explicit*, there is a reference to the relationship within
147+
the source part XML, the key of which is the rId value; changing the rId
148+
would break that mapping.
149+
150+
The **sequence** of relationships in the collection is not significant. The
151+
relationship collection should be regarded as a mapping on rId, not as
152+
a sequence with the index indicated by the numeric suffix of rId. While
153+
PowerPoint observes the convention of using sequential rId values for
154+
the slide relationships of a presentation, for example, this should not be
155+
used to determine slide sequence, nor is it a requirement for package
156+
production (saving a .pptx file).
157+
158+
**reltype**
159+
160+
A clear purpose for reltype is still a mystery to me.
161+
162+
**target_mode**
163+
164+
**target_part**
165+
166+
**target_ref**

doc/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ python-opc
55
Contents:
66

77
.. toctree::
8+
developer/design_narratives
89
:maxdepth: 2
910

1011
Notes

0 commit comments

Comments
 (0)