projet crepp_git/crepp-projects/tracker-solaire/hardware/v1_tht · branche main
pcba_doc_generator.cpython-313.pyc Voir sur GitLab
�

-,Vj����n�SSKrSSKrSSKJrJr SSKJr \"SS55r\"SS55r\"SS	55r	\"S
S55r
\"SS
55rS\S\
S\4SjrS\S\S\\4SjrS\S\S\4SjrS\S\4SjrS\S\S\4SjrSSSSS S!.rS"S#S$S%S&S!.rS'S(S)S*S+S!.rS\S\\
4S,jrS-\S\\4S.jrS\S\\\44S/jrS\S0\S\\\\\	44S1jr1S2krS3rS4\S5\S\4S6jr S7\S8\S\\\\44S9jr!S:\\S\4S;jr"S<\\S\4S=jr#S>\S\4S?jr$S:\\S\4S@jr%SA\
S\4SBjr&SCr'SDr(SSS:\\SF\SG\S\4SHjjr)STS8\S7\SI\S-SG\S\4
SJjjr*SUS:\\SF\S\4SKjjr+\,SL:Xa�SSK-r-\."\-R^5SM:a"\0"SN5 \0"SO5 \-Rb"SP5 \."\-R^5SQ:�a\-R^SQOSEr2\*"\-R^SP\-R^SR\."\-R^5SM:�a\-R^SMOS\25 gg)V�N)�	dataclass�field)�Pathc�<�\rSrSr%\\S'Sr\\S'Sr\\S'Sr	g)	�Variant��nameT�in_bomF�dnp�N)
�__name__�
__module__�__qualname__�__firstlineno__�str�__annotations__r
�boolr�__static_attributes__r��\/home/nico/Documents/crepp_git/CREPP.io/boards/V2.x_pico2/v2.1/scripts/pcba_doc_generator.pyrrs��

�I��F�D���C��rrc�n�\rSrSr%\\S'\\S'\\S'\\S'\\S'\\S'\"\S9r	\\
\S	'S
rg)�	Component��	reference�value�	footprint�description�	datasheetr��default_factory�variantsrN)r
rrrrrrr�listr!rrrrrrrs4���N��J��N����N�	
�I�#�D�9�H�d�7�m�9rrc�*�\rSrSr%\\S'\\S'Srg)�	TestPoint�rrrN�r
rrrrrrrrrr$r$s
���N��rr$c�4�\rSrSr%\\S'\\S'\\S'Srg)�HierarchicalLabel� r	�shaperrNr&rrrr(r( s��

�I��J��rr(c��\rSrSr%\\S'\\S'\"\S9r\\	\S'\"\S9r
\\\S'\"\S9r\\
\S'Sr\\S	'S
rg)�Sheet�&r	�filenamer�
components�labels�test_points��svg_contentrN)r
rrrrrrr"r/rr0r(r1r$r3rrrrr,r,&sQ��

�I��M�"'��"=�J��Y��=�&+�D�&A�F�D�"�#�A�#(��#>�K��i��>��K��rr,�content�start�returnc��Sn[XSU5H.up4US:XaUS-
nMUS:XdMUS-nUS:XdM'XUS-s $ XS$)Nr�(��))�	enumerate)r4r5�depth�i�chs     r�
extract_blockr?4s`��
�E��7�6�?�E�2���
��9��Q�J�E�
�3�Y��Q�J�E���z��Q��U�+�+�
3��6�?�r�keywordc���/nSnSU3nURXC5nUS:XaU$U[U5-[U5:aX[U5-OSnUS;aUR[X55 US-nMn)Nrr8���r2)� �	�
�
r9)�find�len�appendr?)r4r@�blocksr=�searchr5�next_chs       r�find_all_blocksrM@s���
�F�	�A���	�]�F�
����V�'���B�;��
�M�	38�#�f�+�2E��G��2T�'�#�f�+�-�.�Z\���-�-��M�M�-��7�8��A�I��r�blockr	c���[R"S[R"U5S3[R5R	U5nU(aURS5R
5$S$)Nz\(property\s+"z
"\s+"([^"]*)"r9r2)�re�compile�escape�
IGNORECASErK�group�strip)rNr	�ms   r�	get_fieldrWOsW��
�
�
��"�)�)�D�/�*�-�8�"�-�-�	��f�U�m��"#�1�7�7�1�:����*��*rrc�`�[[R"SU[R55$)Nz^TP\d+$)rrP�matchrS)rs r�
is_test_pointrZVs�������Y��
�
�>�?�?r�
sheet_name�
search_dirc
�P�[R"S[R"U5S3[R5[R"S[R"U5S3[R5/n/n[	S5nUR5(a&UR
5(aURU5 UR5(a&UR
5(aURU5 UGH"nUGHn[UR55H�nUR5(dMURUR5(dM<URSSS9n[R"SS	U5n[R"S
S	U5n[R"SSUS
S9n[R"SSUS
S9nSUSS;aURSSS
5nSUSS;aURSSS
5nUR!5s s s $ GM GM% g	)u�
Cherche un fichier SVG correspondant à la feuille :
  - soit "<prefixe>-<sheet_name>.svg"  (sous-feuilles hiérarchiques)
  - soit "<sheet_name>.svg"            (page racine : kicad-cli n'ajoute
                                        pas de préfixe pour la feuille
                                        principale)
La recherche se fait d'abord dans _doc/svg, puis dans le dossier passé en
paramètre. Retourne le contenu SVG nettoyé (sans déclaration XML) ou "".
z^.+-z\.svg$�^z_doc/svg�utf-8�replace)�encoding�errorsz<\?xml[^?]*\?>r2z<!DOCTYPE[^>]*>z(<svg\b[^>]*?)\s+width="[^"]*"z\1r9)�countz(<svg\b[^>]*?)\s+height="[^"]*"zclass=N��z<svgz<svg class="sheet-svg"zstyle=z%<svg style="background-color: white;")rPrQrRrSr�exists�is_dirrI�sorted�iterdir�is_filerYr	�	read_text�subr`rU)	r[r\�patterns�folders_to_check�doc_svg_dir�folder�pattern�	candidate�raws	         r�find_svg_for_sheetrs]s���	�
�
�d�2�9�9�Z�0�1��8�"�-�-�H�
�
�
�a��	�	�*�-�.�f�5�r�}�}�E��H����z�"�K������� 2� 2� 4� 4�����,������z�0�0�2�2����
�+�#���G�#�F�N�N�$4�5�	��$�$�&�&�7�=�=����+H�+H�#�-�-�w�y�-�Q�C��&�&�!2�B��<�C��&�&�!3�R��=�C��&�&�9�5�#�Q��C��&�&�:�E�3�a��C� �s�4�C�y�0�!�k�k�&�2J�A�N���s�4�C�y�0�!�k�k�&�2Y�[\�]���9�9�;�&�'6� �#�.r�Input�Output�Passive�
Bidirectionalz	Tri-State)�input�output�passive�
bidirectional�	tri_statez#d0e8ffz#d4f7d4z#f0f0f0z#fff3cdz#f8d7dau→u←�—u⇄u↕c	��/n[US5H�n[R"SU5n[R"SU5n[R"SU5nU(aU(dMXU(aURS5R	5OSnUR[
URS5URS5U(aUOSS95 M� [US	S
9$)N�hierarchical_labelz \(hierarchical_label\s+"([^"]+)"z\(shape\s+(\w+)\)z\(property\s+"doc"\s+"([^"]*)"r9r2�
pas de doc)r	r*rc��UR$�N)r	)�ls r�<lambda>�+parse_hierarchical_labels.<locals>.<lambda>�s����r��key)rMrPrKrTrUrIr(rg)r4r0rN�name_m�shape_m�desc_m�raw_descs       r�parse_hierarchical_labelsr��s���
�F� ��*>�?�����>��F���)�)�0�%�8���)�)�=�u�E���W��.4�6�<�<��?�(�(�*�"���
�
�'����a���-�-��"�$,��,�
�	�@��&�.�/�/r�symbol_blockc	�N�/n[US5H�n[R"SU5nU(dM#URS5n[	[R"SU55(+n[	[R"SU55nUR[
XEUS95 M� U$)N�variantz\(name\s+"([^"]+)"\)r9z\(in_bom\s+no\)�
\(dnp\s+yes\)�r	r
r)rMrPrKrTrrIr)r�r!�vblockr�r	r
rs       r�parse_variantsr��s����H�!�,�	�:�����2�F�;�������a����"�)�)�$6��?�@�@���b�i�i� 0�&�9�:������T�c�B�C�;��Orc��0nURS5nUS:XaU$[X5n[US5HOn[R"SU5nU(dM#URS5n[
US5[
US5S.X'MQ U$)	Nz(lib_symbolsrB�symbolz\(symbol\s+"([^"]+)"r9�doc�	Datasheet)rr)rGr?rMrPrKrTrW)r4�lib_infor5�	lib_block�	sym_blockr��lib_ids       r�parse_lib_symbolsr��s����H��L�L��(�E���{����g�-�I�$�Y��9�	����2�I�>�������a���$�Y��6�$�Y��<�
���:��Orr�c
�~�/n/n[US5GH�n[R"SU5nU(dM$URS5n[R"SU5nU(aURS5O[	US5nU(a,URS5(dUR
S5(aM�[	US5n	[	US	5n
[	US
5n[	US5n[[R"SU55n
Xa;a6U(dXRS
S5nU(dXRSS5nU=(d SnU=(d Sn[U5(aUR[UUS95 GMr[U5nUR[UU	U
UUU
US95 GM� 0nUH�nURU;aUUUR'M$UURRVs1sHnUR iM nnURH=nUR U;dMUURRRU5 M? M� 0nUHnUR#URU5 M! SnSn[%UR'5US9[%UR'5US94$s snf)Nr�z\(lib_id\s+"([^"]+)"\)r9z\(reference\s+"([^"]+)"\)�	Reference�?�#�Value�	Footprintr�r�r�rr2rr})rr)rrrrrrr!c���[R"SSUR5n[R"SUR5nX(a[	UR554$S4$)Nz\dr2�\d+r)rPrkrrK�intrT)�c�prefix�num_ms   r�
sort_key_comp�6parse_components_and_testpoints.<locals>.sort_key_comp sL������r�1�;�;�/�����6�1�;�;�/���e��E�K�K�M�*�;�;��;�;rc��[R"SUR5nU(a[UR	55$S$)Nr�r�rPrKrr�rT)�tr�s  r�sort_key_tp�4parse_components_and_testpoints.<locals>.sort_key_tp%s.���	�	�&�!�+�+�.��%*�s�5�;�;�=�!�1��1rr�)rMrPrKrTrW�endswith�
startswithr�getrZrIr$r�rrr!r	�
setdefaultrg�values)r4r�r/�test_points_rawr��lib_id_mr��ref_mrrrrrrr!�seen�comp�v�existing_names�seen_tp�tpr�r�s                       r�parse_components_and_testpointsr��sn���J��O�$�W�h�7�	��9�9�6�	�B��������"���I�I�:�I�F��&+�E�K�K��N��9�k�1R�	��I�.�.�s�3�3�y�7K�7K�C�7P�7P���	�7�3���	�;�7�	��	�5�1���	�;�7�	��2�9�9�%5�y�A�B�����&�.�2�2�=�"�E���$�,�0�0��b�A�	�!�*�U���*�U�	���#�#��"�"�9�#�'�$�
�
&�i�0�H����i�#��#�'�#��!��
�E8�X"$�D����>�>��%�#'�D���� �.2�4�>�>�.B�.K�.K�L�.K��a�f�f�.K�N�L��]�]���6�6��/�����(�1�1�8�8��;�#��%'�G������2�<�<��,��<�
2�
	�t�{�{�}�-�0��w�~�~��[�1����%Ms�4J:>�_doc�public�scripts�__pycache__�node_modules�.git)z-backupsz-backupz.backups�path�basec�^�URU5RSSnUHGmT[;a gTR	S5(a g[U4Sj[55(dMG g g![a URSSnNif=f)NrBT�.c3�F># �UHnTRU5v� M g7fr�)r�)�.0�suf�parts  �r�	<genexpr>�_is_ignored.<locals>.<genexpr>Bs����B�-A�c�t�}�}�S�!�!�-A�s�!F)�relative_to�parts�
ValueError�IGNORED_DIR_PARTSr��any�IGNORED_DIR_SUFFIXES)r�r��	rel_partsr�s   @r�_is_ignoredr�8s����$��$�$�T�*�0�0��"�5�	����$�$���?�?�3�����B�-A�B�B�B��
����$��J�J�s��O�	�$�s�A/�/B�
B�
sheets_dir�root_schc���UR5nURU4/nURR51nU1n[UR	S55H�nUR5nXu;aM[X`5(aM,URR5nX�;aMMUR
U5 UR
U5 URURU45 M� U$)uRRetourne la feuille racine EN PREMIER, puis les sous-feuilles.

- La racine est incluse (c'est la page principale du schéma) : elle a elle
  aussi son SVG et ses éventuels composants/signaux.
- Les doublons sont éliminés : un même nom de feuille (stem) n'est retenu
  qu'une fois, et les dossiers de sauvegarde/sortie sont ignorés.
z*.kicad_sch)�resolve�stem�lowerrg�rglobr��addrI)	r�r��
root_resolved�sheets�
seen_stems�
seen_pathsr��resolved�stem_keys	         r�collect_sheetsr�Gs����$�$�&�M�'/�}�}�h�&?�%@�F��-�-�%�%�'�(�J���J��z�'�'�
�6�7���<�<�>���!���t�(�(���9�9�?�?�$���!�����x� ����x� ��
�
�t�y�y�$�'�(�8��Mrr�c���SnSnSnSn/nUH�n[UR5n[SUR55n[UR5n	[SUR55n
Xy-nX�-nU(a[	SU-U-5OSn
URURUUU	U
UUU
S.5 X-
nX(-
nX9-
nXJ-
nM� X-nX$-nU(a[	SU-U-5OSnUUUUUUUUS.$)Nrc3�H# �UHoRS;dMSv� M g7f))r}r2r9N�r)r�r�s  rr��'compute_doc_coverage.<locals>.<genexpr>qs���Y�$4�q�
�
�[�8X���$4���"�	"c3�H# �UHoRS:wdMSv� M g7f)r�r9Nr�)r�r�s  rr�r�ss���R�L�q�M�M�\�4Q���L�r��d)r	�
comp_total�comp_doc�	sig_total�sig_doc�total�
documented�pct)�
global_pct�global_total�global_documented�global_comp_total�global_comp_doc�global_sig_total�global_sig_doc�	per_sheet)rHr/�sumr0�roundrIr	)r�r��global_comp_documentedr��global_sig_documentedr��sheetr�r�r�r�r�r�r�r�r�r�s                 r�compute_doc_coveragerhs?�����������I�����)�)�*�
��Y�E�$4�$4�Y�Y������&�	��R�E�L�L�R�R���&���'�
�16�e�C�*�$�u�,�-�C������J�J�$� �"���$��	
�		�	�+���*���*���(��1�4%�7�L�.�F��BN��s�.�.��=�>�TW�J�!�$�.�.�1�,�/��	�	rr!c�N�U(dg/nUH�n/nUR(dURS5 UR(aURS5 URnU(aUSSR	U5S3-
nURU5 M� SR	U5$)Nr}zhors BOM�DNPz	 <small>(�|z	)</small>�, )r
rIrr	�join)r!r�r��flags�labels     r�format_variantsr	�s������E�
�����x�x��L�L��$��5�5��L�L���������y����%�� 1��;�;�E�
���U����9�9�U��rrc�n�URR5RSS5nSnUR(aSU3nSURS3nSURSURS	US
3nUR
(a�US-
nUR
H�n[RURS5n[RURUR5n[RURS5nURS
:XaSOSn	USURSUSUSUSU	SURS3
-
nM� US-
nUR(a�US-
nURH�n
SU
R;aU
RRS5SOU
Rn[U
R 5nU
R"(aSOSn
U
R"(aSOSnUSU
SU
R$USU
R&SU
RSUS US3-
nM� US-
nOUS!-
nUS"-
nU$)#NrC�-r2zsvg-toggle-u
      <details class="svg-accordion" open>
        <summary class="svg-summary">
          <span class="svg-icon">◈</span>
          Schéma hiérarchique
          <span class="svg-badge">SVG</span>
        </summary>
        <div class="svg-wrap">
          z!
        </div>
      </details>
z
    <section>
      <h2>z <span class="filename">z
</span></h2>
rEu�
      <h3 class="section-label">Signaux hiérarchiques</h3>
      <table>
        <thead>
          <tr>
            <th>Signal</th>
            <th>Direction</th>
            <th>Description</th>
          </tr>
        </thead>
        <tbody>
z#ffffffr�� class="no-doc"z&
          <tr>
            <td><code>zC</code></td>
            <td><span class="badge" style="background:�">z</span></td>
            <td�>�</td>
          </tr>
z         </tbody>
      </table>
u$
      <h3 class="section-label">Composants</h3>
      <table>
        <thead>
          <tr>
            <th>Réf.</th>
            <th>Valeur</th>
            <th>Description</th>
            <th>Boîtier</th>
            <th>Variantes</th>
          </tr>
        </thead>
        <tbody>
�:rBz class="dnp"z# <span class="dnp-badge">DNP</span>z
          <trz>
            <td><code>z%</code></td>
            <td><strong>z</strong></td>
            <td>z</td>
            <td><small>z</small></td>
            <td>u4      <p class='empty'>Aucun composant trouvé.</p>
z    </section>
)r	r�r`r3r.r0�SHAPE_COLORr�r*�SHAPE_TO_DIRECTION�
SHAPE_ICONrr/r�splitr	r!rrr)r�anchor�	svg_block�svg_id�html�lbl�color�	direction�icon�no_docr��fpr!�dnp_cls�dnp_tags               r�
sheet_to_htmlr!�sq��
�Z�Z�
�
�
�
'�
'��S�
1�F��I�����v�h�'������
���	���:�:�,�.�u�~�~�.>�?�
����D�
�|�|���	���<�<�C�#����	�	�9�=�E�*�.�.�s�y�y�#�)�)�D�I�"���s�y�y�"�5�D�-0�_�_��-L�)�RT�F����x�x�j�!7�7<�g�R��v�Q�y�k�R��x�q����)�*�	�
�D� �	
�4�4������
�
	���$�$�D�8;�t�~�~�8M�t�~�~�+�+�C�0��4�SW�Sa�Sa�B�&�t�}�}�5�H�)-���~�r�G�@D���<�b�G����Y���~�~�&�w�i�0�����%��!�!�"�#��t���
��
�
�D�%�	
�4�4���G�G�����D��Krc	�>�/nUH3nURH nURURU45 M" M5 U(dgURSS9 SnUH<upSURS:XaSOSnUSUR
SUS	URS
3-
nM> US-
nU$)Nr2c���[R"SUSR5(a;[[R"SUSR5R	55$S$�Nr�r9rr���xs rr��1global_test_points_section_html.<locals>.<lambda>sN���I�I�f�a��d�n�n�5�5� #�2�9�9�V�Q�q�T�^�^�#D�#J�#J�#L�M� =�;<� =rr�u
    <section id="recap-test-points">
      <h2>Récapitulatif — Points de test <span class="filename">toutes feuilles</span></h2>
      <table>
        <thead>
          <tr>
            <th>Réf.</th>
            <th>Description</th>
          </tr>
        </thead>
        <tbody>
r}rzD
          <tr class="tp-row">
            <td><code class="tp-ref">z</code></td>
            <tdrrz/        </tbody>
      </table>
    </section>
)r1rIr	�sortrr)r��all_tpsrr�r�_sheet_name�no_descs       r�global_test_points_section_htmlr,s���+-�G����#�#�B��N�N�E�J�J��+�,�$�����L�L�=�L�>��D�#���')�~�~��'>�#�B���&�&(�l�l�^�4��y��"�.�.�)�*��	��#�	�@�@�D��Krr�c� �US:�agUS:�agg)N�Pz#22c55e�2z#f59e0bz#ef4444r)r�s r�coverage_bar_colorr0,s��
�b�y��	����ru�2
    @import url('https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,300;14..32,400;14..32,500;14..32,600;14..32,700&family=JetBrains+Mono:wght@400;500&display=swap');

    * { box-sizing: border-box; margin: 0; padding: 0; }

    /* Variables du thème clair (par défaut) */
    :root {
      --bg-primary: #f5f7fb;
      --bg-secondary: #ffffff;
      --bg-card: #ffffff;
      --sidebar-bg: #1a1a2e;
      --sidebar-text: #e8edff;
      --sidebar-text-secondary: #8b95c9;
      --sidebar-accent: #6b8cff;
      --primary: #1a3a5c;
      --accent: #4f46e5;
      --text-primary: #1e293b;
      --text-secondary: #475569;
      --text-muted: #94a3b8;
      --text-white: #1e293b;
      --border: #e2e8f0;
      --border-hover: #cbd5e1;
      --accent-primary: #4f46e5;
      --accent-secondary: #818cf8;
      --accent-glow: rgba(79, 70, 229, 0.1);
      --success: #10b981;
      --success-bg: rgba(16, 185, 129, 0.1);
      --warning: #f59e0b;
      --warning-bg: rgba(245, 158, 11, 0.1);
      --info: #3b82f6;
      --info-bg: rgba(59, 130, 246, 0.1);
      --gold: #fbbf24;
      --gold-bg: rgba(251, 191, 36, 0.1);
      --step: #8b5cf6;
      --step-bg: rgba(139, 92, 246, 0.1);
      --tp-color: #ea580c;
      --danger: #ef4444;
      --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
      --font-mono: 'JetBrains Mono', 'SF Mono', Monaco, monospace;
      --radius: 16px;
      --radius-sm: 10px;
      --shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
      --shadow-hover: 0 4px 6px rgba(0, 0, 0, 0.1);
    }

    /* Thème sombre */
    body.dark-theme {
      --bg-primary: #0f172a;
      --bg-secondary: #1e293b;
      --bg-card: #1e293b;
      --sidebar-bg: #020617;
      --sidebar-text: #e2e8f0;
      --sidebar-text-secondary: #64748b;
      --text-primary: #f1f5f9;
      --text-secondary: #cbd5e1;
      --text-muted: #64748b;
      --text-white: #f1f5f9;
      --border: #334155;
      --border-hover: #475569;
      --accent-primary: #818cf8;
      --accent-secondary: #a5b4fc;
      --accent-glow: rgba(129, 140, 248, 0.15);
      --shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
      --shadow-hover: 0 4px 6px rgba(0, 0, 0, 0.4);
    }

    body {
      font-family: var(--font-sans);
      font-size: 14px;
      background: var(--bg-primary);
      color: var(--text-primary);
      display: flex;
      min-height: 100vh;
      transition: background-color 0.3s ease, color 0.3s ease;
    }

    /* ── BOUTON THÈME ── */
    .theme-toggle {
      position: fixed;
      bottom: 20px;
      right: 20px;
      z-index: 1000;
      background: var(--accent-primary);
      color: white;
      border: none;
      border-radius: 50px;
      padding: 12px 20px;
      cursor: pointer;
      font-size: 14px;
      font-weight: 600;
      display: flex;
      align-items: center;
      gap: 8px;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
      transition: all 0.3s ease;
      font-family: var(--font-sans);
    }

    .theme-toggle:hover {
      transform: scale(1.05);
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
    }

    /* ── SIDEBAR ─────────────────────────────── */
    #sidebar {
      position: fixed;
      top: 0; left: 0; bottom: 0;
      width: 280px;
      background: var(--sidebar-bg);
      color: var(--sidebar-text);
      display: flex;
      flex-direction: column;
      overflow-y: auto;
      z-index: 100;
      box-shadow: 2px 0 12px rgba(0,0,0,0.1);
      transition: background-color 0.3s ease;
    }

    #sidebar-header {
      padding: 1.5rem 1.2rem 1rem;
      border-bottom: 1px solid rgba(255,255,255,0.08);
      background: linear-gradient(135deg, var(--sidebar-bg) 0%, rgba(255,255,255,0.05) 100%);
    }

    #sidebar-header h1 {
      font-size: 1rem;
      font-weight: 700;
      color: #fff;
      letter-spacing: 0.02em;
      line-height: 1.3;
    }

    #sidebar-header p {
      font-size: 0.7rem;
      color: var(--sidebar-text-secondary);
      margin-top: 0.3rem;
      font-family: var(--font-mono);
    }

    /* ── COVERAGE WIDGET ── */
    #coverage-widget {
      padding: 0.85rem 1.2rem;
      border-bottom: 1px solid rgba(255,255,255,0.07);
    }

    #coverage-widget .cov-title {
      font-size: 0.64rem;
      text-transform: uppercase;
      letter-spacing: 0.1em;
      color: var(--sidebar-text-secondary);
      margin-bottom: 0.5rem;
      font-weight: 600;
    }

    .cov-global-row {
      display: flex;
      align-items: center;
      justify-content: space-between;
      margin-bottom: 0.45rem;
    }

    .cov-pct-label {
      font-family: var(--font-mono);
      font-size: 1.3rem;
      font-weight: 600;
      color: #fff;
      line-height: 1;
    }
    .cov-pct-label.warn   { color: #fbbf24; }
    .cov-pct-label.danger { color: #f87171; }

    .cov-sub {
      font-size: 0.65rem;
      color: var(--sidebar-text-secondary);
      text-align: right;
      line-height: 1.5;
    }

    .cov-bar-wrap {
      background: rgba(255,255,255,0.07);
      border-radius: 3px;
      height: 4px;
      overflow: hidden;
    }

    .cov-bar-fill {
      height: 100%;
      border-radius: 3px;
      transition: width 0.4s ease;
    }

    /* ── BOUTON RETOUR ── */
    .back-button {
      margin: 1rem 1.2rem;
      padding: 0.6rem 1rem;
      background: rgba(107, 140, 255, 0.15);
      border: 1px solid var(--accent);
      border-radius: 10px;
      text-decoration: none;
      color: var(--accent);
      font-size: 0.8rem;
      font-weight: 500;
      display: flex;
      align-items: center;
      gap: 0.5rem;
      transition: all 0.25s;
    }

    .back-button:hover {
      background: rgba(107, 140, 255, 0.25);
      transform: translateX(-4px);
    }

    /* ── NAV LINKS ── */
    #sidebar-nav {
      padding: 0.6rem 0;
      flex: 1;
    }

    #sidebar-nav .nav-section-label {
      font-size: 0.62rem;
      text-transform: uppercase;
      letter-spacing: 0.12em;
      color: var(--sidebar-text-secondary);
      padding: 0.5rem 1.2rem 0.25rem;
      font-weight: 600;
    }

    .nav-sheet-link {
      display: block;
      padding: 0.4rem 1.2rem 0.45rem;
      text-decoration: none;
      color: var(--sidebar-text);
      font-size: 0.82rem;
      transition: background 0.15s, color 0.15s;
      border-left: 3px solid transparent;
      position: relative;
    }

    .nav-sheet-link:hover {
      background: rgba(107,140,255,0.08);
      color: #fff;
      border-left-color: var(--sidebar-accent);
    }

    .nav-sheet-inner {
      display: flex;
      align-items: baseline;
      justify-content: space-between;
      gap: 0.4rem;
    }

    .nav-sheet-name {
      flex: 1;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    .nav-sheet-pct {
      font-family: var(--font-mono);
      font-size: 0.65rem;
      opacity: 0.55;
      flex-shrink: 0;
    }

    .nav-sheet-bar {
      height: 2px;
      border-radius: 2px;
      margin-top: 0.25rem;
      background: rgba(255,255,255,0.05);
      overflow: hidden;
    }

    .nav-sheet-bar-fill {
      height: 100%;
      border-radius: 2px;
      opacity: 0.6;
    }

    #sidebar-nav a.tp-link {
      display: flex;
      align-items: center;
      gap: 0.5rem;
      padding: 0.45rem 1.2rem;
      text-decoration: none;
      color: #fb923c;
      font-size: 0.82rem;
      transition: background 0.15s, color 0.15s;
      border-left: 3px solid transparent;
    }

    #sidebar-nav a.tp-link:hover {
      background: rgba(249,115,22,0.12);
      color: #fdba74;
      border-left-color: var(--tp-color);
    }

    #sidebar-nav a .nav-icon {
      font-size: 0.75rem;
      opacity: 0.7;
      width: 16px;
      text-align: center;
    }

    /* ── MAIN CONTENT ── */
    #main {
      margin-left: 280px;
      flex: 1;
      padding: 2rem 2.5rem;
      max-width: calc(100vw - 280px);
    }

    section {
      background: var(--bg-card);
      border: 1px solid var(--border);
      border-radius: var(--radius);
      padding: 1.5rem 2rem;
      margin-bottom: 1.5rem;
      box-shadow: var(--shadow);
      transition: all 0.3s ease;
    }

    section:hover {
      border-color: var(--border-hover);
      box-shadow: var(--shadow-hover);
    }

    section h2 {
      font-size: 1.1rem;
      color: var(--text-primary);
      border-left: 4px solid var(--accent);
      padding-left: 0.8rem;
      margin-bottom: 1.2rem;
      font-weight: 600;
    }

    #recap-test-points h2 {
      border-left-color: var(--tp-color);
    }

    .filename {
      font-size: 0.7rem;
      font-weight: normal;
      color: var(--text-secondary);
      font-family: var(--font-mono);
      margin-left: 0.5rem;
    }

    .section-label {
      font-size: 0.75rem;
      color: var(--text-secondary);
      margin: 1.2rem 0 0.6rem;
      text-transform: uppercase;
      letter-spacing: 0.07em;
      font-weight: 600;
    }

    /* ── ACCORDÉON SVG (ouvert par défaut) ── */
    .svg-accordion {
      margin-bottom: 1.2rem;
      border: 1px solid var(--border);
      border-radius: 12px;
      overflow: hidden;
    }

    .svg-summary {
      display: flex;
      align-items: center;
      gap: 0.5rem;
      padding: 0.6rem 1rem;
      cursor: pointer;
      font-size: 0.82rem;
      font-weight: 600;
      color: var(--text-primary);
      background: rgba(0,0,0,0.02);
      user-select: none;
      list-style: none;
      transition: background 0.15s;
    }

    body.dark-theme .svg-summary {
      background: rgba(255,255,255,0.03);
    }

    .svg-summary::-webkit-details-marker { display: none; }
    .svg-summary::marker { display: none; }

    .svg-summary:hover {
      background: rgba(79, 70, 229, 0.08);
    }

    details[open] .svg-summary {
      background: rgba(79, 70, 229, 0.05);
      border-bottom: 1px solid var(--border);
    }

    .svg-summary::after {
      content: "▸";
      margin-left: auto;
      font-size: 0.7rem;
      color: var(--text-secondary);
      transition: transform 0.2s;
    }

    details[open] .svg-summary::after {
      transform: rotate(90deg);
    }

    .svg-icon {
      color: var(--accent);
      font-size: 0.9rem;
    }

    .svg-badge {
      font-family: var(--font-mono);
      font-size: 0.6rem;
      background: var(--accent);
      color: white;
      padding: 0.1rem 0.4rem;
      border-radius: 6px;
      letter-spacing: 0.05em;
    }

    .svg-wrap {
      padding: 1rem;
      background: white;
      overflow-x: auto;
      transition: background 0.3s ease;
    }

    body.dark-theme .svg-wrap {
      background: #ffffff;
    }

    .svg-wrap .sheet-svg,
    .svg-wrap svg {
      width: 100%;
      height: auto;
      max-height: 900px;
      display: block;
      background: white;
    }

    /* ── TABLES ── */
    table {
      width: 100%;
      border-collapse: collapse;
      margin-bottom: 0.5rem;
      font-size: 0.85rem;
    }

    /* En-tête de tableau : fond uni sombre + texte réellement blanc.
       (Avant : dégradé partant de --sidebar-bg avec color:var(--text-white),
       or --text-white vaut #1e293b en thème clair → texte sombre sur fond
       sombre, donc bandeau illisible.) */
    thead tr {
      background: var(--sidebar-bg);
      color: #ffffff;
    }
    thead th {
      padding: 0.6rem 0.9rem;
      text-align: left;
      font-weight: 600;
      font-size: 0.8rem;
      letter-spacing: 0.03em;
      color: #ffffff;
      border-bottom: 2px solid var(--accent-primary);
    }

    tbody tr:nth-child(even) { background: rgba(0,0,0,0.02); }
    body.dark-theme tbody tr:nth-child(even) { background: rgba(255,255,255,0.02); }
    tbody tr:hover { background: rgba(79, 70, 229, 0.08); }
    tbody td { padding: 0.5rem 0.9rem; border-bottom: 1px solid var(--border); vertical-align: middle; }

    .tp-row { border-left: 3px solid var(--tp-color); }
    .tp-ref { color: var(--tp-color); font-weight: bold; }

    code {
      font-family: var(--font-mono);
      font-size: 0.85em;
    }

    .badge {
      display: inline-block;
      padding: 0.2rem 0.6rem;
      border-radius: 20px;
      font-size: 0.7rem;
      font-weight: 600;
      color: #333;
    }

    .no-doc  { color: var(--text-muted); font-style: italic; }
    .empty   { color: var(--text-muted); font-style: italic; padding: 0.5rem 0; }

    .dnp     { opacity: 0.45; }
    .dnp-badge {
      background: var(--danger);
      color: white;
      font-size: 0.6rem;
      padding: 0.1rem 0.4rem;
      border-radius: 4px;
      margin-left: 0.3rem;
      vertical-align: middle;
    }

    small { color: var(--text-secondary); }

    /* ── RESPONSIVE ── */
    @media (max-width: 768px) {
      #sidebar { width: 0px; display: none; }
      #main { margin-left: 0; padding: 1rem; max-width: 100vw; }
      .theme-toggle { bottom: 10px; right: 10px; padding: 8px 16px; font-size: 12px; }
    }
u�
    // Gestion du thème clair/sombre
    function initTheme() {
        const savedTheme = localStorage.getItem('theme');
        if (savedTheme === 'dark') {
            document.body.classList.add('dark-theme');
            updateThemeButton(true);
        } else {
            document.body.classList.remove('dark-theme');
            updateThemeButton(false);
        }
    }
    
    function updateThemeButton(isDark) {
        const btn = document.getElementById('theme-toggle-btn');
        if (btn) {
            if (isDark) {
                btn.innerHTML = '☀️ Thème clair';
            } else {
                btn.innerHTML = '🌙 Thème sombre';
            }
        }
    }
    
    function toggleTheme() {
        if (document.body.classList.contains('dark-theme')) {
            document.body.classList.remove('dark-theme');
            localStorage.setItem('theme', 'light');
            updateThemeButton(false);
        } else {
            document.body.classList.add('dark-theme');
            localStorage.setItem('theme', 'dark');
            updateThemeButton(true);
        }
    }
    
    // Initialiser le thème au chargement
    initTheme();
�
../index.html�project_name�
pcb_index_urlc���SSKJn [SU55n[U5nUSnUS:aSO	US:aSOS	n[	U5nS
USUSUS
SUSSUSSUSSUSUS3n	SUS3n
USVs0sHo�SUS_M
 nnSn
UH�nUR
R
5RSS5nURUR
S5n[	U5nUR(aSOS	nU
S US!UUR
S"US#USUS$3-
n
M� U(a
U
S%-
n
U
S&-
n
S	nUHEnUR
R
5RSS5nUS'US3[U5-S(--
nMG U[U5-
nS)US*[S+US,UR5R5S-[U5S.US/U	S0U
S1U
S2US3[ S43$s snf)5Nr)�datec3�L# �UHn[UR5v� M g7fr�)rHr1)r��ss  rr�� generate_html.<locals>.<genexpr>gs���6�v�!�3�q�}�}�%�%�v�s�"$r�r/�dangerr.�warnr2z�
    <div id="coverage-widget">
      <div class="cov-title">Couverture globale</div>
      <div class="cov-global-row">
        <div class="cov-pct-label r
z0%</div>
        <div class="cov-sub">
          r��/r�z cmp<br>
          r�r�zq sig
        </div>
      </div>
      <div class="cov-bar-wrap">
        <div class="cov-bar-fill" style="width:z%; background:z!"></div>
      </div>
    </div>
z
    <a href="uF" class="back-button">
      <span>←</span> Retour aux PCB
    </a>
r�r	r�z.<div class="nav-section-label">Feuilles</div>
rCrr�u◈ z    <a href="#zc" class="nav-sheet-link">
      <div class="nav-sheet-inner">
        <span class="nav-sheet-name">z,</span>
        <span class="nav-sheet-pct">zm%</span>
      </div>
      <div class="nav-sheet-bar">
        <div class="nav-sheet-bar-fill" style="width:z"></div>
      </div>
    </a>
zR    <div class="nav-section-label" style="margin-top:0.6rem">Points de test</div>
ui    <a href="#recap-test-points" class="tp-link"><span class="nav-icon">🔍</span>Récapitulatif TP</a>
z	<div id="z</div>u�<!DOCTYPE html>
<html lang="fr">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Documentation — z</title>
  <style>u </style>
</head>
<body>

  <!-- ── BOUTON CHANGEMENT DE THÈME ── -->
  <button id="theme-toggle-btn" class="theme-toggle" onclick="toggleTheme()">
    🌙 Thème sombre
  </button>

  <!-- ── SIDEBAR ── -->
  <aside id="sidebar">
    <div id="sidebar-header">
      <h1>u</h1>
      <p>Généré le z<br>u feuille(s) · z TP</p>
    </div>

    z
    z#

    <nav id="sidebar-nav">
      uM
    </nav>
  </aside>

  <!-- ── MAIN ── -->
  <main id="main">
    z
  </main>

  <script>
    z
  </script>

</body>
</html>
)�datetimer5r�rr0r	r�r`r�r3r!r,�CSS�today�	isoformatrH�
JAVASCRIPT)r�r2r3r5�total_tp�coverage�g_pct�pct_cls�bar_col�cov_html�back_buttonr7�pct_by_name�	nav_linksrrr�r�has_svg�bodys                    r�
generate_htmlrLds�����6�v�6�6�H�$�V�,�H���%�E� �2�:�x�e�b�j�F�b�G�!�%�(�G�#�$+�)�2�e�W�5��%�&�
'�q��2E�)F�(G�H��$�%�
&�a��1C�(D�'E�F0�16�w�n�W�I�N��H�"��_���K�19��0E�F�0E�1�V�9�a��h�&�0E�K�F�A�I����*�*�"�"�$�,�,�S�#�6���/�/�%�*�*�c�2��$�S�)��!�-�-�&�2�����x�0&�&-�Y�u�z�z�l�;%�%(�E�*6�7:�U�.���P�
	�		�	�� ��j�j�	��B�	B�	��D������!�!�#�+�+�C��5���)�F�8�2�&��u�)=�=��H�H���	�+�F�3�3�D��
)�>�*
�

����.���z�z�|�-�-�/�0��S��[�M��QY�PZ�[��J���M���k��
�F���L��I)�)��?Gs�:Gryc��[U5R5n[U5R5nUR5(d[SU35eUR5(d[SU35e[	SU35 [	SUS35 URSS9n[
U5n[X5nU(d�[	S5 [XV5up�[U5n
S	nURU[S
54H"n[URU5nU(dM" O [URURUU
U	US9/n
[	S[U5S
[U	5S[U
5S35 GO;[	S[U5S35 /n
UGHup�[	SUSUR!UR5S35 URSS9n[
U5n0UEUEn[UU5up�[U5n
S	nURU[S
54H%n[X�5nU(dM[	SU35  O U(d[	SUS35 [	S[U5S
[U	5S[U
5S35 U
R#[UURUU
U	US95 GM U(a[U5OSn[%U
5nU(a2UR&R)5S:Xa[+X�RS9nO[-X�RUS9nU(aUR/USS9 [	SU35 O[	U5 UUU
4$)NuSchéma racine introuvable : zDossier introuvable : uSchéma racine    : zDossier feuilles : rEr_)rauY  Aucune sous-feuille hiérarchique trouvée : documentation de la feuille racine seule.
r2r�)r	r.r/r0r1r3u  → z composant(s), z point(s) de test, u signal(aux) hiérarchique(s)z  u feuille(s) trouvée(s) :
z  Traitement : z (r:u    → SVG trouvé dans u!    → Pas de SVG trouvé pour '�'u    → z.md)r2)r2r3u
Documentation écrite dans : )rr�re�FileNotFoundError�printrjr�r�r�r��parentrsr�r,r	rHr�rIr�suffixr��generate_markdown_fallbackrL�
write_text)r�r�ryr3�	root_path�root_content�root_lib�
sub_sheetsr/r1r0r3r\r�r	r��
sheet_content�	sheet_lib�
merged_lib�output_pathrB�results                      r�document_projectr^�sZ���h��'�'�)�I��j�!�)�)�+�J�������"?�	�{� K�L�L�������"8��� E�F�F�	� ���
,�-�	��
�|�2�
.�/��&�&��&�8�L�$�\�2�H��
�6�J��	�j�k�"A�,�"Y��
�*�<�8����$�+�+�Z��c��C�J�,�Y�^�^�Z�H�K��{��D������^�^�!��#�#�

���	��s�:��'��s�;�7G�6H�H[�\_�`f�\g�[h�iF�G�	H�
��3�z�?�#�#>�?�@���$�J�D��O�D�6��D�,<�,<�Z�=N�=N�,O�+P�PQ�R�S� �N�N�G�N�<�M�-�m�<�I�5�x�5�9�5�J�&E�m�U_�&`�#�J�5�m�D�F��K�#�{�{�J��S�	�B�
�0��B���;��5�j�\�B�C��	C�
��9�$��q�A�B��H�S��_�-�_�S��=M�<N�Na�be�fl�bm�an�oL�M�
N��M�M�%�����%��'�'�
�
�'%�8#)�$�v�,�d�K�#�F�+�H��{�)�)�/�/�1�U�:�+�F���P���v�N�N�R_�`������v���8�
�/��}�=�>�
�f�
��8�V�#�#rc���SU3SSSSS/n[U5nUSUSS3SUS	S
USS3SS
S/-
nUSH9nURSUSSUSSUSS
USSUSS
USS3
5 M; U/SQ-
nUGH�nUSUR3SSURS3S/-
nUR(a�U/SQ-
nURH\n[
R
URUR5nURSURSUSURS35 M^ URS5 UR(dM�U/SQ-
nURH�nS UR;aURRS 5S!OURn	S"RS#UR55=(d S$n
UR(aS%OSnURSURUSUR SURSU	SU
S35 M� URS5 GM� UVVs/sH#oDR"Ho�RU4PM M% n
nnU
(a_U
R%S&S'9 U/S(Q-
nU
H1up�URSURSURS35 M3 URS5 S)RU5$s snnf)*Nu# Documentation composants — r2u4Généré automatiquement depuis les schémas KiCad.�---z)## Couverture de documentation globale : r��%r8r�r;r�u éléments documentés)z/| Feuille | Couverture | Composants | Signaux |z/|---------|------------|------------|---------|r�z| r	z | r�z% | r�r�r�r�z |)r2r`r2z## zFichier : `�`)u### Signaux hiérarchiquesr2z$| Signal | Direction | Description |z$|--------|-----------|-------------|)z### Composantsr2u7| Réf. | Valeur | Description | Boîtier | Variantes |z5|------|--------|-------------|---------|-----------|rrBrc3�# �UH=nURUR(dSOS-UR(aSOS-v� M? g7f)z (hors BOM)r2z (DNP)Nr�)r�r�s  rr��-generate_markdown_fallback.<locals>.<genexpr>Rs9���%�*���F�F�1�8�8�m��D�TU�TY�TY��_a�b�*�s�AAr}u
 ⚠️DNPc���[R"SUSR5(a;[[R"SUSR5R	55$S$r$r�r%s rr��,generate_markdown_fallback.<locals>.<lambda>\sP���	�	�&�!�A�$�.�.�9�9�$'�r�y�y���1����'H�'N�'N�'P�#Q�$A�?@�$Arr�)r`r2u6## Récapitulatif — Points de test (toutes feuilles)r2u| Réf. | Description |z|------|-------------|rE)rrIr	r.r0rr�r*rr/rrrr!rrrr1r()r�r2�linesrBr7rrrr�rr!rr�r)r*s               rrSrS*s��
)�,��8�"�>��E�2�
�E�
$�F�+�H�	�
3�H�\�4J�3K�1�M�
�H�(�)�*�!�H�^�,D�+E�E]�^�
�9�9���E��k�
"��
���r�!�F�)��C��%��z��a�
�m�_�A�a��o�EV�VY�Z[�\e�Zf�Yg�gh�ij�kv�iw�hx�xz�{�|�#�	�_��E���
�C��
�
�|�$�b�K����7G�q�*I�2�N�N���<�<���
�E�
�|�|��.�2�2�3�9�9�c�i�i�H�	����r�#�(�(��3�y�k��S�_�_�<M�R�P�Q�$�
�L�L���������
�E�
�(�(��<?�4�>�>�<Q�4�>�>�/�/��4�R�8�W[�We�We���9�9�%�!�]�]�%�����'+�h�h�l�B�����r�$�.�.�!1�#��c�$�*�*��S��IY�IY�HZ�Z]�^`�]a�ad�em�dn�np�q�r�)�
�L�L���9�<&,�D�V��m�m�����|�m�|�V�G�D�����A��	B�
�
�	
�� '�O�K��L�L�2�b�l�l�^�3�r�~�~�.>�b�A�B� '�
���R���9�9�U����Es�*K$�__main__�zUUsage : py list_pinout.py <root.kicad_sch> <dossier_feuilles> [output.html|output.md]zJExemple : py list_pinout.py CREPP.io.kicad_sch Modules/ documentation.htmlr9��)r2r1)Nr1)r2)3rP�os�dataclassesrr�pathlibrrrr$r(r,rr�r?r"rMrWrrZrsrrrr�r��dictr��tupler�r�r�r�r�rr	r!r,r0r=r@rLr^rSr
�sysrH�argvrP�exit�pcb_urlrrr�<module>rus���	�	�(�������
�:�:��:�����������
�����	�3�	�s�	�s�	��S��3��4��9��+�S�+��+��+�@�S�@�T�@�3�3�3�D�3�S�3�v���$� ����������������
�0�s�0�t�4E�/F�0�"
��
��g��
��s��t�C��I���$L�
�L� �L�
�4�	�?�D��O�+�,�L�d��;���d��$��4���t��t���U�3��9�=M�8N��B.��e��.��.�j�d�7�m����"W��W�3�W�t!�D��K�!�C�!�H�C��C��B��J&�
�Rk�$�u�+�k�S�k�c�k�hk�k�dQ$�s�Q$��Q$�S�4�Z�Q$�_b�Q$�y|�Q$�h>�t�E�{�>�#�>�s�>�B�z���
�3�8�8�}�q��
�e�f�
�Z�[������!����]�Q�.�c�h�h�q�k�O�G��S�X�X�a�[�#�(�(�1�+�c�#�(�(�m�a�>O�s�x�x��{�UY�[b�c�r