easyvista-python-client 0.4.0__py3-none-any.whl → 0.4.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,4 +5,4 @@
5
5
  live only in ``__init__``.
6
6
  """
7
7
 
8
- __version__ = "0.4.0"
8
+ __version__ = "0.4.2"
@@ -26,9 +26,10 @@ page lists them too. The glue below covers what the three libraries leave
26
26
  out: plain text, line breaks a browser does not show, bold and italic
27
27
  CommonMark would not close, link targets, and an mdformat set up without
28
28
  its nesting cap and with its quadratic lookups made linear. A body nested
29
- too deeply for the stack is read as its text (:func:`_text_of`); anything
30
- else that fails raises
31
- :class:`~easyvista_python_client.EasyvistaContentError`.
29
+ too deeply for the stack, or on which the conversion raises ``ValueError``
30
+ -- markdownify does for a ``colspan`` or ``start`` it cannot read as a
31
+ number -- is read as its text (:func:`_text_of`); anything else that fails
32
+ raises :class:`~easyvista_python_client.EasyvistaContentError`.
32
33
 
33
34
  A memo with no HTML element in it is read as literal lines, a line break
34
35
  per line. How EasyVista's web UI displays such a memo is unverified: the
@@ -138,6 +139,11 @@ _EMPHASIS = frozenset({"b", "strong", "em", "i"})
138
139
  _BEFORE, _AFTER = "data-ev-before", "data-ev-after"
139
140
  _NUMBER = "data-ev-number" # an ordered item's number (_Converter.convert_li)
140
141
 
142
+ #: The elements kept as raw tags (:meth:`_Converter.convert_u`), and the
143
+ #: attribute marking one that holds a block (:func:`_note_blocks`).
144
+ _RAW_INLINE = frozenset({"u", "mark", "ins"})
145
+ _HOLDS_BLOCK = "data-ev-block"
146
+
141
147
  #: Text split into leading line breaks and spaces, content, trailing ones.
142
148
  #: The content ends on its last character that is neither, found greedily:
143
149
  #: a lazy ``.*?`` rescanned the run after it at every step, quadratic.
@@ -330,6 +336,33 @@ def _note_sides(root: Tag) -> None:
330
336
  element[_AFTER] = " "
331
337
 
332
338
 
339
+ def _note_blocks(root: Tag) -> None:
340
+ """Mark each ``<u>``, ``<mark>`` or ``<ins>`` that holds a block.
341
+
342
+ Markdown has no inline tag around blocks: such a tag wrapped round them
343
+ showed a table, a list or a heading as its Markdown source, and round a
344
+ ``<pre>`` left a fence open to the end of the body. One walk: a block
345
+ marks the open ones from the innermost out and stops at one already
346
+ marked, whose holders were marked with it, so each is marked once
347
+ however deeply they nest.
348
+ """
349
+
350
+ holders: list[Tag] = []
351
+ for node, entering in _walk(root):
352
+ if not isinstance(node, Tag):
353
+ continue
354
+ if node.name in _RAW_INLINE:
355
+ if entering:
356
+ holders.append(node)
357
+ else:
358
+ holders.pop()
359
+ elif entering and node.name in _BLOCKS:
360
+ for holder in reversed(holders):
361
+ if holder.has_attr(_HOLDS_BLOCK):
362
+ break
363
+ holder[_HOLDS_BLOCK] = ""
364
+
365
+
333
366
  def _punctuation(char: str) -> bool:
334
367
  """Return whether CommonMark counts ``char`` as punctuation."""
335
368
 
@@ -426,8 +459,14 @@ class _Converter(MarkdownConverter):
426
459
  convert_strike = convert_s
427
460
 
428
461
  def convert_u(self, el: Tag, text: str, parent_tags: set[str]) -> str:
429
- """Underlined or highlighted text: CommonMark has neither, so raw HTML."""
462
+ """Underlined or highlighted text: CommonMark has neither, so raw HTML.
430
463
 
464
+ Round a block the tag is dropped and the blocks kept, except on the
465
+ one line of a cell or a heading, where the blocks are inline text.
466
+ """
467
+
468
+ if el.has_attr(_HOLDS_BLOCK) and "_inline" not in parent_tags:
469
+ return text
431
470
  return self._markup(el, text, parent_tags, "", el.name)
432
471
 
433
472
  convert_mark = convert_ins = convert_u
@@ -705,15 +744,30 @@ def html_to_markdown(html: str) -> str:
705
744
  _flatten_nested_tables(soup)
706
745
  _drop_trailing_breaks(soup)
707
746
  _note_sides(soup)
747
+ _note_blocks(soup)
708
748
  return str(_FORMATTER.render(_CONVERTER.convert_soup(soup))).strip()
709
749
 
710
750
 
751
+ #: A link as cmark-gfm writes one: an ``href``, an optional ``title``, nothing else.
752
+ _RENDERED_LINK = re.compile(r'<a href="[^"]*"(?: title="[^"]*")?>')
753
+
754
+ #: What EasyVista's own editor writes on a link: without it the memo view opens the
755
+ #: link in place, inside EasyVista's window, rather than in a new one.
756
+ _NEW_WINDOW = ' target="_blank" rel="noopener noreferrer"'
757
+
758
+
711
759
  def markdown_to_html(markdown: str) -> str:
712
- """Render Markdown as HTML: CommonMark with GFM tables, through cmark-gfm."""
760
+ """Render Markdown as HTML: CommonMark with GFM tables, through cmark-gfm.
761
+
762
+ Every link opens in a new window, the way a link written in EasyVista's
763
+ editor does: ``target="_blank" rel="noopener noreferrer"`` is added to each
764
+ link cmark-gfm writes. Reading ignores both attributes.
765
+ """
713
766
 
714
767
  html: str = cmarkgfm.markdown_to_html_with_extensions(
715
768
  markdown, options=_RENDER_OPTIONS, extensions=["table"]
716
769
  )
770
+ html = _RENDERED_LINK.sub(lambda link: link.group(0)[:-1] + _NEW_WINDOW + ">", html)
717
771
  return html.strip()
718
772
 
719
773
 
@@ -762,8 +816,10 @@ class EasyvistaContentConverter:
762
816
  ------
763
817
  EasyvistaContentError
764
818
  The value could not be converted. A body nested too deeply for
765
- the stack left is read as its text instead, so this is a
766
- backstop.
819
+ the stack left, or on which the conversion raises
820
+ ``ValueError`` (a ``colspan`` or ``start`` markdownify cannot
821
+ read as a number, among others), is read as its text instead,
822
+ so this is a backstop.
767
823
  RecursionError
768
824
  Only when called from within a few frames of the recursion
769
825
  limit, where no stack is left even to report the failure as
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: easyvista-python-client
3
- Version: 0.4.0
3
+ Version: 0.4.2
4
4
  Summary: Typed Python client for the EasyVista Service Manager REST API
5
5
  Project-URL: Homepage, https://github.com/baraline/easyvista_python_client
6
6
  Project-URL: Documentation, https://easyvista-python-client.readthedocs.io/en/latest/
@@ -2,7 +2,7 @@ easyvista_python_client/__init__.py,sha256=AkPNxN1iaQhprPYShcqCEx03b0d4qi6b98MCF
2
2
  easyvista_python_client/_fields.py,sha256=L-9niigMP6vAMLR1rhY0KpmY0Zo_FeTkROr3dYd_Qwo,2164
3
3
  easyvista_python_client/_html.py,sha256=KftxdX4vHptQrOMqfWM-9I3g03UAA5YRmqwnLjI2Ir4,1276
4
4
  easyvista_python_client/_transport.py,sha256=AZItqLNOfgj1qTfC0ajxiKOPxXGnh7S0mGJE7VilfLU,3034
5
- easyvista_python_client/_version.py,sha256=PLASpND1O0wa5cbzoM9DAQcnNa0as2-w4-AiN1nIIzQ,290
5
+ easyvista_python_client/_version.py,sha256=Qs1bD7HLZeviaRaWtnZfFdMaFFMcmAU9-o4uKWhIj2E,290
6
6
  easyvista_python_client/config.py,sha256=Zdzv2GB7Hma-z6RiR0820l4KPFn_EZxfmuQrS4RYlek,12361
7
7
  easyvista_python_client/context.py,sha256=_5PEjH4a2jM8Ks51YEes--CESt1vBXlK87y0s8UutHQ,13597
8
8
  easyvista_python_client/directory.py,sha256=BD44sgJgAAhcz2d0Eyqpv4fjdc9HCustI_izR4qwoyo,7820
@@ -25,7 +25,7 @@ easyvista_python_client/_sync/_concurrency.py,sha256=zeCtzdrMQa9thzdV6A5sdP8Ojoj
25
25
  easyvista_python_client/_sync/_transport.py,sha256=JwEclG90LO9wrPxv1aEy8sQxHbeWVyyi61oEy4zsHx8,27537
26
26
  easyvista_python_client/_sync/client.py,sha256=I7H999YpssGhGozMo7Dxu4qkkfTMKzJjAHvR8fEyyC8,117586
27
27
  easyvista_python_client/content/__init__.py,sha256=Bqf40LdL00OyOfq0IqR5uBSEBL1QKvVwll8u4dQ0lW0,878
28
- easyvista_python_client/content/conversion.py,sha256=H4FqOtU5ecKudlrCXe5gZsCb68NIK6sWs6YA8RwIz_I,32784
28
+ easyvista_python_client/content/conversion.py,sha256=LFkNnKHJfsHEhcHwANYDMnKSX0Q9POan84lbxGiFj_M,35249
29
29
  easyvista_python_client/models/__init__.py,sha256=dCN1GPDWqu5zraEuGiCZaUGXyNQiK3yCuAC18Fh6NL4,47
30
30
  easyvista_python_client/models/action.py,sha256=m-R_n9S89yq3acjXsBM7FY05edW4jH97YIw5B-VG6zI,33405
31
31
  easyvista_python_client/models/asset.py,sha256=_cKeGOORSSLbqvXf_rQ2K00KM6K4DJdnqDvvhg7rhAg,2047
@@ -44,7 +44,7 @@ easyvista_python_client/resources/discovery.py,sha256=2XKV_sfP8Evlb_aDc4gi-aP-W3
44
44
  easyvista_python_client/resources/documents.py,sha256=FUfRDeAJu1qF9MvqLFwRtkxJvBC85SGEuoO85n_Qupk,6526
45
45
  easyvista_python_client/resources/employees.py,sha256=7X_hTRnk7T-GMNldDANmdnv2TgFZCfhIwgz7-PEDKaY,1790
46
46
  easyvista_python_client/resources/requests.py,sha256=qNksnO6RST6smHnT9eEkSbxR0iHXrW-ADkM3J_oQ4To,5380
47
- easyvista_python_client-0.4.0.dist-info/METADATA,sha256=Zpb6cKuhSROijleXwUYeNiaSnYuH_5UO6rCQP-9utP0,13094
48
- easyvista_python_client-0.4.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
49
- easyvista_python_client-0.4.0.dist-info/licenses/LICENSE,sha256=COAKFzPjsNCUJS82NnwBj20wPEHE34Dl8GzGZzaQWR0,1093
50
- easyvista_python_client-0.4.0.dist-info/RECORD,,
47
+ easyvista_python_client-0.4.2.dist-info/METADATA,sha256=jwB2EAUsFzBnTfCbdZJjiT9-dulWiPS3R-PhgABBTDk,13094
48
+ easyvista_python_client-0.4.2.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
49
+ easyvista_python_client-0.4.2.dist-info/licenses/LICENSE,sha256=COAKFzPjsNCUJS82NnwBj20wPEHE34Dl8GzGZzaQWR0,1093
50
+ easyvista_python_client-0.4.2.dist-info/RECORD,,