Merge branch 'dev' into feature-multicolor-wires
# Conflicts: # .gitignore # src/batch.py # src/wireviz.py # src/wv_colors.py
25
.github/workflows/main.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
name: Create Examples
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
max-parallel: 4
|
||||
matrix:
|
||||
python-version: [3.7, 3.8]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Setup Graphviz
|
||||
uses: ts-graphviz/setup-graphviz@v1
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install .
|
||||
- name: Create Examples
|
||||
run: PYTHONPATH=$(pwd)/src:$PYTHONPATH cd src/wireviz/ && python build_examples.py
|
||||
14
.gitignore
vendored
@ -1,12 +1,18 @@
|
||||
.DS_Store
|
||||
temp/
|
||||
.eggs
|
||||
__pycache__
|
||||
.*.swp
|
||||
*.egg-info
|
||||
*.pyc
|
||||
build
|
||||
data
|
||||
dist
|
||||
venv/
|
||||
|
||||
.vscode/
|
||||
|
||||
.idea/
|
||||
|
||||
|
||||
# IntelliJ Stuff
|
||||
# Jetbrains Stuff
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
|
||||
@ -17,13 +17,25 @@ WireViz is a tool for easily documenting cables, wiring harnesses and connector
|
||||
* [DIN 47100](https://en.wikipedia.org/wiki/DIN_47100) (WT/BN/GN/YE/GY/PK/BU/RD/BK/VT/...)
|
||||
* [IEC 62](https://en.wikipedia.org/wiki/Electronic_color_code#Color_band_system) (BN/RD/OR/YE/GN/BU/VT/GY/WT/BK/...)
|
||||
* Understands wire gauge in mm² or AWG
|
||||
* Optionally auto-calculates and displays AWG equivalent when specifying mm²
|
||||
* Optionally auto-calculates equivalent gauge between mm² and AWG
|
||||
* Allows more than one connector per side, as well as loopbacks
|
||||
* Allows for easy-autorouting for 1-to-1 wiring
|
||||
* Generates BOM (Bill of Materials)
|
||||
|
||||
_Note_: WireViz is not designed to represent the complete wiring of a system. Its main aim is to document the construction of individual wires and harnesses.
|
||||
|
||||
## Installation
|
||||
|
||||
WireWiz requires GraphViz to be installed in order to work. See the [GraphViz download page](https://graphviz.org/download/) for OS-specific instructions.
|
||||
|
||||
Installation of the WireWiz package and its Python dependencies can be done using pip after cloning the repository:
|
||||
|
||||
```
|
||||
git clone <repo url>
|
||||
cd <working copy>
|
||||
pip3 install -e .
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Demo 01
|
||||
@ -51,7 +63,7 @@ cables:
|
||||
|
||||
connections:
|
||||
-
|
||||
- X1: [5,2,1]
|
||||
- X1: [5,2,3]
|
||||
- W1: [1,2,3]
|
||||
- X2: [1,3,2]
|
||||
-
|
||||
@ -79,7 +91,7 @@ as well as the [example gallery](examples/readme.md) to see more of what WireViz
|
||||
## Usage
|
||||
|
||||
```
|
||||
$ python3 wireviz.py ~/path/to/file/mywire.yml
|
||||
$ wireviz ~/path/to/file/mywire.yml
|
||||
```
|
||||
|
||||
This will output the following files
|
||||
@ -92,14 +104,23 @@ mywire.bom.tsv BOM (bill of materials) as tab-separated text file
|
||||
mywire.html HTML page with wiring diagram and BOM embedded
|
||||
```
|
||||
|
||||
### (Re-)Building the example projects
|
||||
|
||||
If you would like to rebuild all of the included demos, examples and tutorials, use the ```build_examples.py``` script:
|
||||
|
||||
```cd src/wireviz
|
||||
./build_examples.py
|
||||
```
|
||||
## Status
|
||||
|
||||
This is very much a [work in progress](todo.md). Source code, API, syntax and functionality may change wildly at any time.
|
||||
This is very much a [work in progress](https://github.com/formatc1702/WireViz/projects/1). Source code, API, syntax and functionality may change wildly at any time.
|
||||
|
||||
## Requirements
|
||||
|
||||
Developed and tested using Python 3.7; might not work with older Python versions.
|
||||
|
||||
Ubuntu 18.04 LTS users in particular may need to separately install Python 3.7 or above, as that comes with Python 3.6 as the included system Python install.
|
||||
|
||||
## License
|
||||
|
||||
GNU GPLv3
|
||||
@ -1,4 +1,4 @@
|
||||
Item Qty Unit Designators
|
||||
D-Sub, female, 9 pins 1 X1
|
||||
Molex KK 254, female, 3 pins 1 X2
|
||||
Cable 3 x 0.25 mm² shielded 0.2 m W1
|
||||
Connector, D-Sub, female, 9 pins 1 X1
|
||||
Connector, Molex KK 254, female, 3 pins 1 X2
|
||||
Cable, 3 x 0.25 mm² shielded 0.2 m W1
|
||||
|
||||
|
@ -13,9 +13,9 @@ graph {
|
||||
X1:p2r:e -- W1:w2:w
|
||||
W1:w2:e -- X2:p3l:w
|
||||
edge [color="#000000:#00ff00:#000000"]
|
||||
X1:p1r:e -- W1:w3:w
|
||||
X1:p3r:e -- W1:w3:w
|
||||
W1:w3:e -- X2:p2l:w
|
||||
edge [color="#000000"]
|
||||
X1:p5r:e -- W1:ws:w
|
||||
W1 [label=<<table border="0" cellspacing="0" cellpadding="0"><tr><td><table border="0" cellspacing="0" cellpadding="3" cellborder="1"><tr><td colspan="4">W1</td></tr><tr><td>3x</td><td>0.25 mm²</td><td>+ S</td><td>0.2 m</td></tr></table></td></tr><tr><td> </td></tr><tr><td><table border="0" cellspacing="0" cellborder="0"><tr><td>X1:5</td><td>WH</td><td>X2:1</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#ffffff" border="2" sides="tb" port="w1"></td></tr><tr><td>X1:2</td><td>BN</td><td>X2:3</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#666600" border="2" sides="tb" port="w2"></td></tr><tr><td>X1:1</td><td>GN</td><td>X2:2</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#00ff00" border="2" sides="tb" port="w3"></td></tr><tr><td> </td></tr><tr><td>X1:5</td><td>Shield</td><td><!-- s_out --></td></tr><tr><td colspan="3" cellpadding="0" height="6" border="2" sides="b" port="ws"></td></tr><tr><td> </td></tr></table></td></tr></table>> fillcolor=white margin=0 shape=box style=""]
|
||||
W1 [label=<<table border="0" cellspacing="0" cellpadding="0"><tr><td><table border="0" cellspacing="0" cellpadding="3" cellborder="1"><tr><td colspan="4">W1</td></tr><tr><td>3x</td><td>0.25 mm²</td><td>+ S</td><td>0.2 m</td></tr></table></td></tr><tr><td> </td></tr><tr><td><table border="0" cellspacing="0" cellborder="0"><tr><td>X1:5</td><td>WH</td><td>X2:1</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#ffffff" border="2" sides="tb" port="w1"></td></tr><tr><td>X1:2</td><td>BN</td><td>X2:3</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#666600" border="2" sides="tb" port="w2"></td></tr><tr><td>X1:3</td><td>GN</td><td>X2:2</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#00ff00" border="2" sides="tb" port="w3"></td></tr><tr><td> </td></tr><tr><td>X1:5</td><td>Shield</td><td><!-- s_out --></td></tr><tr><td colspan="3" cellpadding="0" height="6" border="2" sides="b" port="ws"></td></tr><tr><td> </td></tr></table></td></tr></table>> fillcolor=white margin=0 shape=box style=""]
|
||||
}
|
||||
|
||||
@ -83,7 +83,7 @@
|
||||
<polygon fill="#666600" stroke="transparent" stroke-width="2" points="304.5,-170 304.5,-176 467.5,-176 467.5,-170 304.5,-170"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="305.5,-171 466.5,-171 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="466.5,-175 305.5,-175 "/>
|
||||
<text text-anchor="start" x="316" y="-156.8" font-family="arial" font-size="14.00">X1:1</text>
|
||||
<text text-anchor="start" x="316" y="-156.8" font-family="arial" font-size="14.00">X1:3</text>
|
||||
<text text-anchor="start" x="375" y="-156.8" font-family="arial" font-size="14.00">GN</text>
|
||||
<text text-anchor="start" x="428" y="-156.8" font-family="arial" font-size="14.00">X2:2</text>
|
||||
<polygon fill="#00ff00" stroke="transparent" stroke-width="2" points="304.5,-145 304.5,-151 467.5,-151 467.5,-145 304.5,-145"/>
|
||||
@ -112,9 +112,9 @@
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M160,-194C225.5,-195.63 234.57,-147.63 304,-146"/>
|
||||
<path fill="none" stroke="#00ff00" stroke-width="2" d="M160,-196C227.46,-196 236.54,-148 304,-148"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M160,-198C229.43,-196.37 238.5,-148.37 304,-150"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M160,-148C223.76,-148.02 239.75,-146.02 304,-146"/>
|
||||
<path fill="none" stroke="#00ff00" stroke-width="2" d="M160,-150C224.01,-150 239.99,-148 304,-148"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M160,-152C224.25,-151.98 240.24,-149.98 304,-150"/>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge7" class="edge">
|
||||
@ -168,4 +168,4 @@
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<h1>Bill of Materials</h1><table style="border:1px solid #000000; font-size: 14pt; border-spacing: 0px"><tr><th align="left" style="border:1px solid #000000; padding: 8px">Item</th><th align="left" style="border:1px solid #000000; padding: 8px">Qty</th><th align="left" style="border:1px solid #000000; padding: 8px">Unit</th><th align="left" style="border:1px solid #000000; padding: 8px">Designators</th></tr><tr><td style="border:1px solid #000000; padding: 4px">D-Sub, female, 9 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">1</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X1</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Molex KK 254, female, 3 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">1</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X2</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Cable 3 x 0.25 mm² shielded</td><td align="right" style="border:1px solid #000000; padding: 4px">0.2</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1</td></tr></table></body></html>
|
||||
<h1>Bill of Materials</h1><table style="border:1px solid #000000; font-size: 14pt; border-spacing: 0px"><tr><th align="left" style="border:1px solid #000000; padding: 8px">Item</th><th align="left" style="border:1px solid #000000; padding: 8px">Qty</th><th align="left" style="border:1px solid #000000; padding: 8px">Unit</th><th align="left" style="border:1px solid #000000; padding: 8px">Designators</th></tr><tr><td style="border:1px solid #000000; padding: 4px">Connector, D-Sub, female, 9 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">1</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X1</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Connector, Molex KK 254, female, 3 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">1</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X2</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Cable, 3 x 0.25 mm² shielded</td><td align="right" style="border:1px solid #000000; padding: 4px">0.2</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1</td></tr></table></body></html>
|
||||
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 45 KiB |
@ -83,7 +83,7 @@
|
||||
<polygon fill="#666600" stroke="transparent" stroke-width="2" points="304.5,-170 304.5,-176 467.5,-176 467.5,-170 304.5,-170"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="305.5,-171 466.5,-171 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="466.5,-175 305.5,-175 "/>
|
||||
<text text-anchor="start" x="316" y="-156.8" font-family="arial" font-size="14.00">X1:1</text>
|
||||
<text text-anchor="start" x="316" y="-156.8" font-family="arial" font-size="14.00">X1:3</text>
|
||||
<text text-anchor="start" x="375" y="-156.8" font-family="arial" font-size="14.00">GN</text>
|
||||
<text text-anchor="start" x="428" y="-156.8" font-family="arial" font-size="14.00">X2:2</text>
|
||||
<polygon fill="#00ff00" stroke="transparent" stroke-width="2" points="304.5,-145 304.5,-151 467.5,-151 467.5,-145 304.5,-145"/>
|
||||
@ -112,9 +112,9 @@
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M160,-194C225.5,-195.63 234.57,-147.63 304,-146"/>
|
||||
<path fill="none" stroke="#00ff00" stroke-width="2" d="M160,-196C227.46,-196 236.54,-148 304,-148"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M160,-198C229.43,-196.37 238.5,-148.37 304,-150"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M160,-148C223.76,-148.02 239.75,-146.02 304,-146"/>
|
||||
<path fill="none" stroke="#00ff00" stroke-width="2" d="M160,-150C224.01,-150 239.99,-148 304,-148"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M160,-152C224.25,-151.98 240.24,-149.98 304,-150"/>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge7" class="edge">
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@ -18,7 +18,7 @@ cables:
|
||||
|
||||
connections:
|
||||
-
|
||||
- X1: [5,2,1]
|
||||
- X1: [5,2,3]
|
||||
- W1: [1,2,3]
|
||||
- X2: [1,3,2]
|
||||
-
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
Item Qty Unit Designators
|
||||
Crimp ferrule, 0.25 mm² 2
|
||||
Molex KK 254, female, 4 pins 2 X2, X3
|
||||
Molex KK 254, female, 5 pins 1 X4
|
||||
Molex KK 254, female, 8 pins 1 X1
|
||||
Cable 2 x 0.25 mm² 0.3 m W4
|
||||
Wire 0.14 mm² BK 0.9 m W1, W2, W3
|
||||
Wire 0.14 mm² BU 0.3 m W3
|
||||
Wire 0.14 mm² GN 0.6 m W1, W2
|
||||
Wire 0.14 mm² OG 0.3 m W3
|
||||
Wire 0.14 mm² RD 0.6 m W1, W2
|
||||
Wire 0.14 mm² VT 0.3 m W3
|
||||
Wire 0.14 mm² YE 0.6 m W1, W2
|
||||
Connector, Crimp ferrule, 0.25 mm² 2
|
||||
Connector, Molex KK 254, female, 4 pins 2 X2, X3
|
||||
Connector, Molex KK 254, female, 5 pins 1 X4
|
||||
Connector, Molex KK 254, female, 8 pins 1 X1
|
||||
Cable, 2 x 0.25 mm² 0.3 m W4
|
||||
Wire, 0.14 mm², BK 0.9 m W1, W2, W3
|
||||
Wire, 0.14 mm², BU 0.3 m W3
|
||||
Wire, 0.14 mm², GN 0.6 m W1, W2
|
||||
Wire, 0.14 mm², OG 0.3 m W3
|
||||
Wire, 0.14 mm², RD 0.6 m W1, W2
|
||||
Wire, 0.14 mm², VT 0.3 m W3
|
||||
Wire, 0.14 mm², YE 0.6 m W1, W2
|
||||
|
||||
|
@ -8,7 +8,7 @@ graph {
|
||||
X2 [label="X2|{Molex KK 254|female|4-pin}|{{<p1l>1|<p2l>2|<p3l>3|<p4l>4}|{GND|+5V|SCL|SDA}}"]
|
||||
X3 [label="X3|{Molex KK 254|female|4-pin}|{{<p1l>1|<p2l>2|<p3l>3|<p4l>4}|{GND|+5V|SCL|SDA}}"]
|
||||
X4 [label="X4|{Molex KK 254|female|5-pin}|{{<p1l>1|<p2l>2|<p3l>3|<p4l>4|<p5l>5}|{GND|+12V|MISO|MOSI|SCK}}"]
|
||||
F1 [label=<
|
||||
_F1 [label=<
|
||||
|
||||
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" CELLPADDING="2"><TR>
|
||||
<TD PORT="p1l"> Crimp ferrule, 0.25 mm² </TD>
|
||||
@ -18,7 +18,7 @@ graph {
|
||||
|
||||
|
||||
> margin=0 orientation=180 shape=none style=filled]
|
||||
F2 [label=<
|
||||
_F2 [label=<
|
||||
|
||||
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" CELLPADDING="2"><TR>
|
||||
<TD PORT="p1l"> Crimp ferrule, 0.25 mm² </TD>
|
||||
@ -68,9 +68,9 @@ graph {
|
||||
W3:w4:e -- X4:p5l:w
|
||||
W3 [label=<<table border="0" cellspacing="0" cellpadding="0"><tr><td><table border="0" cellspacing="0" cellpadding="3" cellborder="1"><tr><td colspan="3">W3</td></tr><tr><td>4x</td><td>0.14 mm² (26 AWG)</td><td>0.3 m</td></tr></table></td></tr><tr><td> </td></tr><tr><td><table border="0" cellspacing="0" cellborder="0"><tr><td>X1:1</td><td>BK</td><td>X4:1</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#000000" border="2" sides="tb" port="w1"></td></tr><tr><td>X1:5</td><td>BU</td><td>X4:3</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#0066ff" border="2" sides="tb" port="w2"></td></tr><tr><td>X1:6</td><td>OG</td><td>X4:4</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#ff8000" border="2" sides="tb" port="w3"></td></tr><tr><td>X1:7</td><td>VT</td><td>X4:5</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#8000ff" border="2" sides="tb" port="w4"></td></tr><tr><td> </td></tr></table></td></tr></table>> fillcolor=white margin=0 shape=box style="filled,dashed"]
|
||||
edge [color="#000000:#000000:#000000"]
|
||||
F1:e -- W4:w1:w
|
||||
_F1:e -- W4:w1:w
|
||||
edge [color="#000000:#ff0000:#000000"]
|
||||
F2:e -- W4:w2:w
|
||||
_F2:e -- W4:w2:w
|
||||
edge [color="#000000:#000000:#000000"]
|
||||
W4:w1:e -- X4:p1l:w
|
||||
edge [color="#000000:#ff0000:#000000"]
|
||||
|
||||
@ -341,9 +341,9 @@
|
||||
<polyline fill="none" stroke="black" points="780,-191.5 898,-191.5 "/>
|
||||
<text text-anchor="middle" x="839" y="-176.3" font-family="arial" font-size="14.00">SCK</text>
|
||||
</g>
|
||||
<!-- F1 -->
|
||||
<!-- _F1 -->
|
||||
<g id="node5" class="node">
|
||||
<title>F1</title>
|
||||
<title>_F1</title>
|
||||
<polygon fill="white" stroke="transparent" points="15.5,-60 190.5,-60 190.5,-96 15.5,-96 15.5,-60"/>
|
||||
<text text-anchor="start" x="19" y="-73.8" font-family="arial" font-size="14.00"> Crimp ferrule, 0.25 mm²  </text>
|
||||
<text text-anchor="start" x="180" y="-73.8" font-family="arial" font-size="14.00">  </text>
|
||||
@ -374,24 +374,24 @@
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="547,-37 351,-37 "/>
|
||||
<text text-anchor="start" x="374.5" y="-18.8" font-family="arial" font-size="14.00"> </text>
|
||||
</g>
|
||||
<!-- F1--W4 -->
|
||||
<!-- _F1--W4 -->
|
||||
<g id="edge25" class="edge">
|
||||
<title>F1:e--W4:w</title>
|
||||
<title>_F1:e--W4:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M192,-76C261.21,-76.64 277.86,-58.64 350,-58"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M192,-78C262.68,-78 279.32,-60 350,-60"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M192,-80C264.14,-79.36 280.79,-61.36 350,-62"/>
|
||||
</g>
|
||||
<!-- F2 -->
|
||||
<!-- _F2 -->
|
||||
<g id="node6" class="node">
|
||||
<title>F2</title>
|
||||
<title>_F2</title>
|
||||
<polygon fill="white" stroke="transparent" points="15.5,0 190.5,0 190.5,-36 15.5,-36 15.5,0"/>
|
||||
<text text-anchor="start" x="19" y="-13.8" font-family="arial" font-size="14.00"> Crimp ferrule, 0.25 mm²  </text>
|
||||
<text text-anchor="start" x="180" y="-13.8" font-family="arial" font-size="14.00">  </text>
|
||||
<polygon fill="none" stroke="black" points="15.5,-7.5 15.5,-28.5 190.5,-28.5 190.5,-7.5 15.5,-7.5"/>
|
||||
</g>
|
||||
<!-- F2--W4 -->
|
||||
<!-- _F2--W4 -->
|
||||
<g id="edge26" class="edge">
|
||||
<title>F2:e--W4:w</title>
|
||||
<title>_F2:e--W4:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M192,-16C264.05,-16.6 280.8,-33.6 350,-33"/>
|
||||
<path fill="none" stroke="#ff0000" stroke-width="2" d="M192,-18C262.63,-18 279.37,-35 350,-35"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M192,-20C261.2,-19.4 277.95,-36.4 350,-37"/>
|
||||
@ -496,4 +496,4 @@
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<h1>Bill of Materials</h1><table style="border:1px solid #000000; font-size: 14pt; border-spacing: 0px"><tr><th align="left" style="border:1px solid #000000; padding: 8px">Item</th><th align="left" style="border:1px solid #000000; padding: 8px">Qty</th><th align="left" style="border:1px solid #000000; padding: 8px">Unit</th><th align="left" style="border:1px solid #000000; padding: 8px">Designators</th></tr><tr><td style="border:1px solid #000000; padding: 4px">Crimp ferrule, 0.25 mm²</td><td align="right" style="border:1px solid #000000; padding: 4px">2</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px"></td></tr><tr><td style="border:1px solid #000000; padding: 4px">Molex KK 254, female, 4 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">2</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X2, X3</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Molex KK 254, female, 5 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">1</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X4</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Molex KK 254, female, 8 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">1</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X1</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Cable 2 x 0.25 mm²</td><td align="right" style="border:1px solid #000000; padding: 4px">0.3</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W4</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire 0.14 mm² BK</td><td align="right" style="border:1px solid #000000; padding: 4px">0.9</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1, W2, W3</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire 0.14 mm² BU</td><td align="right" style="border:1px solid #000000; padding: 4px">0.3</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W3</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire 0.14 mm² GN</td><td align="right" style="border:1px solid #000000; padding: 4px">0.6</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1, W2</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire 0.14 mm² OG</td><td align="right" style="border:1px solid #000000; padding: 4px">0.3</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W3</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire 0.14 mm² RD</td><td align="right" style="border:1px solid #000000; padding: 4px">0.6</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1, W2</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire 0.14 mm² VT</td><td align="right" style="border:1px solid #000000; padding: 4px">0.3</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W3</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire 0.14 mm² YE</td><td align="right" style="border:1px solid #000000; padding: 4px">0.6</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1, W2</td></tr></table></body></html>
|
||||
<h1>Bill of Materials</h1><table style="border:1px solid #000000; font-size: 14pt; border-spacing: 0px"><tr><th align="left" style="border:1px solid #000000; padding: 8px">Item</th><th align="left" style="border:1px solid #000000; padding: 8px">Qty</th><th align="left" style="border:1px solid #000000; padding: 8px">Unit</th><th align="left" style="border:1px solid #000000; padding: 8px">Designators</th></tr><tr><td style="border:1px solid #000000; padding: 4px">Connector, Crimp ferrule, 0.25 mm²</td><td align="right" style="border:1px solid #000000; padding: 4px">2</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px"></td></tr><tr><td style="border:1px solid #000000; padding: 4px">Connector, Molex KK 254, female, 4 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">2</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X2, X3</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Connector, Molex KK 254, female, 5 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">1</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X4</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Connector, Molex KK 254, female, 8 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">1</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X1</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Cable, 2 x 0.25 mm²</td><td align="right" style="border:1px solid #000000; padding: 4px">0.3</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W4</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire, 0.14 mm², BK</td><td align="right" style="border:1px solid #000000; padding: 4px">0.9</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1, W2, W3</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire, 0.14 mm², BU</td><td align="right" style="border:1px solid #000000; padding: 4px">0.3</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W3</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire, 0.14 mm², GN</td><td align="right" style="border:1px solid #000000; padding: 4px">0.6</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1, W2</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire, 0.14 mm², OG</td><td align="right" style="border:1px solid #000000; padding: 4px">0.3</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W3</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire, 0.14 mm², RD</td><td align="right" style="border:1px solid #000000; padding: 4px">0.6</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1, W2</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire, 0.14 mm², VT</td><td align="right" style="border:1px solid #000000; padding: 4px">0.3</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W3</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire, 0.14 mm², YE</td><td align="right" style="border:1px solid #000000; padding: 4px">0.6</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1, W2</td></tr></table></body></html>
|
||||
@ -341,9 +341,9 @@
|
||||
<polyline fill="none" stroke="black" points="780,-191.5 898,-191.5 "/>
|
||||
<text text-anchor="middle" x="839" y="-176.3" font-family="arial" font-size="14.00">SCK</text>
|
||||
</g>
|
||||
<!-- F1 -->
|
||||
<!-- _F1 -->
|
||||
<g id="node5" class="node">
|
||||
<title>F1</title>
|
||||
<title>_F1</title>
|
||||
<polygon fill="white" stroke="transparent" points="15.5,-60 190.5,-60 190.5,-96 15.5,-96 15.5,-60"/>
|
||||
<text text-anchor="start" x="19" y="-73.8" font-family="arial" font-size="14.00"> Crimp ferrule, 0.25 mm²  </text>
|
||||
<text text-anchor="start" x="180" y="-73.8" font-family="arial" font-size="14.00">  </text>
|
||||
@ -374,24 +374,24 @@
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="547,-37 351,-37 "/>
|
||||
<text text-anchor="start" x="374.5" y="-18.8" font-family="arial" font-size="14.00"> </text>
|
||||
</g>
|
||||
<!-- F1--W4 -->
|
||||
<!-- _F1--W4 -->
|
||||
<g id="edge25" class="edge">
|
||||
<title>F1:e--W4:w</title>
|
||||
<title>_F1:e--W4:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M192,-76C261.21,-76.64 277.86,-58.64 350,-58"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M192,-78C262.68,-78 279.32,-60 350,-60"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M192,-80C264.14,-79.36 280.79,-61.36 350,-62"/>
|
||||
</g>
|
||||
<!-- F2 -->
|
||||
<!-- _F2 -->
|
||||
<g id="node6" class="node">
|
||||
<title>F2</title>
|
||||
<title>_F2</title>
|
||||
<polygon fill="white" stroke="transparent" points="15.5,0 190.5,0 190.5,-36 15.5,-36 15.5,0"/>
|
||||
<text text-anchor="start" x="19" y="-13.8" font-family="arial" font-size="14.00"> Crimp ferrule, 0.25 mm²  </text>
|
||||
<text text-anchor="start" x="180" y="-13.8" font-family="arial" font-size="14.00">  </text>
|
||||
<polygon fill="none" stroke="black" points="15.5,-7.5 15.5,-28.5 190.5,-28.5 190.5,-7.5 15.5,-7.5"/>
|
||||
</g>
|
||||
<!-- F2--W4 -->
|
||||
<!-- _F2--W4 -->
|
||||
<g id="edge26" class="edge">
|
||||
<title>F2:e--W4:w</title>
|
||||
<title>_F2:e--W4:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M192,-16C264.05,-16.6 280.8,-33.6 350,-33"/>
|
||||
<path fill="none" stroke="#ff0000" stroke-width="2" d="M192,-18C262.63,-18 279.37,-35 350,-35"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M192,-20C261.2,-19.4 277.95,-36.4 350,-37"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
@ -1,3 +1,3 @@
|
||||
Item Qty Unit Designators
|
||||
Molex KK 254, female, 4 pins 2 X1, X2
|
||||
Cable 4 x 0.25 mm² shielded 0.2 m W1
|
||||
Connector, Molex KK 254, female, 4 pins 2 X1, X2
|
||||
Cable, 4 x 0.25 mm² shielded 0.2 m W1
|
||||
|
||||
|
@ -172,4 +172,4 @@
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<h1>Bill of Materials</h1><table style="border:1px solid #000000; font-size: 14pt; border-spacing: 0px"><tr><th align="left" style="border:1px solid #000000; padding: 8px">Item</th><th align="left" style="border:1px solid #000000; padding: 8px">Qty</th><th align="left" style="border:1px solid #000000; padding: 8px">Unit</th><th align="left" style="border:1px solid #000000; padding: 8px">Designators</th></tr><tr><td style="border:1px solid #000000; padding: 4px">Molex KK 254, female, 4 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">2</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X1, X2</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Cable 4 x 0.25 mm² shielded</td><td align="right" style="border:1px solid #000000; padding: 4px">0.2</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1</td></tr></table></body></html>
|
||||
<h1>Bill of Materials</h1><table style="border:1px solid #000000; font-size: 14pt; border-spacing: 0px"><tr><th align="left" style="border:1px solid #000000; padding: 8px">Item</th><th align="left" style="border:1px solid #000000; padding: 8px">Qty</th><th align="left" style="border:1px solid #000000; padding: 8px">Unit</th><th align="left" style="border:1px solid #000000; padding: 8px">Designators</th></tr><tr><td style="border:1px solid #000000; padding: 4px">Connector, Molex KK 254, female, 4 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">2</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X1, X2</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Cable, 4 x 0.25 mm² shielded</td><td align="right" style="border:1px solid #000000; padding: 4px">0.2</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1</td></tr></table></body></html>
|
||||
@ -1,4 +1,5 @@
|
||||
Item Qty Unit Designators
|
||||
Molex Micro-Fit, female, 2 pins 3 X2, X3, X4
|
||||
Molex Micro-Fit, male, 2 pins 1 X1
|
||||
Cable 2 x 0.25 mm² 0.6 m W1, W2, W3
|
||||
Connector, Molex Micro-Fit, female, 2 pins 3 X2, X3, X4
|
||||
Connector, Molex Micro-Fit, male, 2 pins 1 X1
|
||||
Cable, 2 x 0.25 mm² 0.4 m W1, W2
|
||||
Cable, 2 x 20 AWG 0.2 m W3
|
||||
|
||||
|
@ -28,5 +28,5 @@ graph {
|
||||
edge [color="#000000:#ff0000:#000000"]
|
||||
X1:p2r:e -- W3:w2:w
|
||||
W3:w2:e -- X4:p2l:w
|
||||
W3 [label=<<table border="0" cellspacing="0" cellpadding="0"><tr><td><table border="0" cellspacing="0" cellpadding="3" cellborder="1"><tr><td colspan="3">W3</td></tr><tr><td>2x</td><td>0.25 mm² (24 AWG)</td><td>0.2 m</td></tr></table></td></tr><tr><td> </td></tr><tr><td><table border="0" cellspacing="0" cellborder="0"><tr><td>X1:1</td><td>BK</td><td>X4:1</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#000000" border="2" sides="tb" port="w1"></td></tr><tr><td>X1:2</td><td>RD</td><td>X4:2</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#ff0000" border="2" sides="tb" port="w2"></td></tr><tr><td> </td></tr></table></td></tr></table>> fillcolor=white margin=0 shape=box style=""]
|
||||
W3 [label=<<table border="0" cellspacing="0" cellpadding="0"><tr><td><table border="0" cellspacing="0" cellpadding="3" cellborder="1"><tr><td colspan="3">W3</td></tr><tr><td>2x</td><td>20 AWG (0.75 mm²)</td><td>0.2 m</td></tr></table></td></tr><tr><td> </td></tr><tr><td><table border="0" cellspacing="0" cellborder="0"><tr><td>X1:1</td><td>BK</td><td>X4:1</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#000000" border="2" sides="tb" port="w1"></td></tr><tr><td>X1:2</td><td>RD</td><td>X4:2</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#ff0000" border="2" sides="tb" port="w2"></td></tr><tr><td> </td></tr></table></td></tr></table>> fillcolor=white margin=0 shape=box style=""]
|
||||
}
|
||||
|
||||
@ -119,7 +119,7 @@
|
||||
<polygon fill="none" stroke="black" points="348,-84 348,-107 371,-107 371,-84 348,-84"/>
|
||||
<text text-anchor="start" x="352" y="-91.8" font-family="arial" font-size="14.00">2x</text>
|
||||
<polygon fill="none" stroke="black" points="371,-84 371,-107 503,-107 503,-84 371,-84"/>
|
||||
<text text-anchor="start" x="375" y="-91.8" font-family="arial" font-size="14.00">0.25 mm² (24 AWG)</text>
|
||||
<text text-anchor="start" x="375" y="-91.8" font-family="arial" font-size="14.00">20 AWG (0.75 mm²)</text>
|
||||
<polygon fill="none" stroke="black" points="503,-84 503,-107 546,-107 546,-84 503,-84"/>
|
||||
<text text-anchor="start" x="507" y="-91.8" font-family="arial" font-size="14.00">0.2 m</text>
|
||||
<text text-anchor="start" x="445" y="-72.8" font-family="arial" font-size="14.00"> </text>
|
||||
@ -255,4 +255,4 @@
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<h1>Bill of Materials</h1><table style="border:1px solid #000000; font-size: 14pt; border-spacing: 0px"><tr><th align="left" style="border:1px solid #000000; padding: 8px">Item</th><th align="left" style="border:1px solid #000000; padding: 8px">Qty</th><th align="left" style="border:1px solid #000000; padding: 8px">Unit</th><th align="left" style="border:1px solid #000000; padding: 8px">Designators</th></tr><tr><td style="border:1px solid #000000; padding: 4px">Molex Micro-Fit, female, 2 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">3</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X2, X3, X4</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Molex Micro-Fit, male, 2 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">1</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X1</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Cable 2 x 0.25 mm²</td><td align="right" style="border:1px solid #000000; padding: 4px">0.6</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1, W2, W3</td></tr></table></body></html>
|
||||
<h1>Bill of Materials</h1><table style="border:1px solid #000000; font-size: 14pt; border-spacing: 0px"><tr><th align="left" style="border:1px solid #000000; padding: 8px">Item</th><th align="left" style="border:1px solid #000000; padding: 8px">Qty</th><th align="left" style="border:1px solid #000000; padding: 8px">Unit</th><th align="left" style="border:1px solid #000000; padding: 8px">Designators</th></tr><tr><td style="border:1px solid #000000; padding: 4px">Connector, Molex Micro-Fit, female, 2 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">3</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X2, X3, X4</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Connector, Molex Micro-Fit, male, 2 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">1</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X1</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Cable, 2 x 0.25 mm²</td><td align="right" style="border:1px solid #000000; padding: 4px">0.4</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1, W2</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Cable, 2 x 20 AWG</td><td align="right" style="border:1px solid #000000; padding: 4px">0.2</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W3</td></tr></table></body></html>
|
||||
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 79 KiB |
@ -119,7 +119,7 @@
|
||||
<polygon fill="none" stroke="black" points="348,-84 348,-107 371,-107 371,-84 348,-84"/>
|
||||
<text text-anchor="start" x="352" y="-91.8" font-family="arial" font-size="14.00">2x</text>
|
||||
<polygon fill="none" stroke="black" points="371,-84 371,-107 503,-107 503,-84 371,-84"/>
|
||||
<text text-anchor="start" x="375" y="-91.8" font-family="arial" font-size="14.00">0.25 mm² (24 AWG)</text>
|
||||
<text text-anchor="start" x="375" y="-91.8" font-family="arial" font-size="14.00">20 AWG (0.75 mm²)</text>
|
||||
<polygon fill="none" stroke="black" points="503,-84 503,-107 546,-107 546,-84 503,-84"/>
|
||||
<text text-anchor="start" x="507" y="-91.8" font-family="arial" font-size="14.00">0.2 m</text>
|
||||
<text text-anchor="start" x="445" y="-72.8" font-family="arial" font-size="14.00"> </text>
|
||||
|
||||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
@ -22,6 +22,7 @@ cables:
|
||||
<<: *wire_power # create from template
|
||||
W3:
|
||||
<<: *wire_power # create from template
|
||||
gauge: 20 awg
|
||||
|
||||
connections:
|
||||
-
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
Item Qty Unit Designators
|
||||
Molex Micro-Fit, female, 2 pins 3 X2, X3, X4
|
||||
Molex Micro-Fit, male, 2 pins 1 X1
|
||||
Wire 0.25 mm² BK 0.6 m W1
|
||||
Wire 0.25 mm² RD 0.6 m W1
|
||||
Connector, Molex Micro-Fit, female, 2 pins 3 X2, X3, X4
|
||||
Connector, Molex Micro-Fit, male, 2 pins 1 X1
|
||||
Wire, 0.25 mm², BK 0.6 m W1
|
||||
Wire, 0.25 mm², RD 0.6 m W1
|
||||
|
||||
|
@ -225,4 +225,4 @@
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<h1>Bill of Materials</h1><table style="border:1px solid #000000; font-size: 14pt; border-spacing: 0px"><tr><th align="left" style="border:1px solid #000000; padding: 8px">Item</th><th align="left" style="border:1px solid #000000; padding: 8px">Qty</th><th align="left" style="border:1px solid #000000; padding: 8px">Unit</th><th align="left" style="border:1px solid #000000; padding: 8px">Designators</th></tr><tr><td style="border:1px solid #000000; padding: 4px">Molex Micro-Fit, female, 2 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">3</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X2, X3, X4</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Molex Micro-Fit, male, 2 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">1</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X1</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire 0.25 mm² BK</td><td align="right" style="border:1px solid #000000; padding: 4px">0.6</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire 0.25 mm² RD</td><td align="right" style="border:1px solid #000000; padding: 4px">0.6</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1</td></tr></table></body></html>
|
||||
<h1>Bill of Materials</h1><table style="border:1px solid #000000; font-size: 14pt; border-spacing: 0px"><tr><th align="left" style="border:1px solid #000000; padding: 8px">Item</th><th align="left" style="border:1px solid #000000; padding: 8px">Qty</th><th align="left" style="border:1px solid #000000; padding: 8px">Unit</th><th align="left" style="border:1px solid #000000; padding: 8px">Designators</th></tr><tr><td style="border:1px solid #000000; padding: 4px">Connector, Molex Micro-Fit, female, 2 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">3</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X2, X3, X4</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Connector, Molex Micro-Fit, male, 2 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">1</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X1</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire, 0.25 mm², BK</td><td align="right" style="border:1px solid #000000; padding: 4px">0.6</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire, 0.25 mm², RD</td><td align="right" style="border:1px solid #000000; padding: 4px">0.6</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1</td></tr></table></body></html>
|
||||
@ -1,8 +1,8 @@
|
||||
Item Qty Unit Designators
|
||||
Crimp ferrule 12
|
||||
Wire 0.25 mm² BN 0.2 m W1
|
||||
Wire 0.25 mm² BU 0.2 m W1
|
||||
Wire 0.25 mm² GN 0.2 m W1
|
||||
Wire 0.25 mm² OG 0.2 m W1
|
||||
Wire 0.25 mm² RD 0.2 m W1
|
||||
Wire 0.25 mm² YE 0.2 m W1
|
||||
Connector, Crimp ferrule 12
|
||||
Wire, 0.25 mm², BN 0.2 m W1
|
||||
Wire, 0.25 mm², BU 0.2 m W1
|
||||
Wire, 0.25 mm², GN 0.2 m W1
|
||||
Wire, 0.25 mm², OG 0.2 m W1
|
||||
Wire, 0.25 mm², RD 0.2 m W1
|
||||
Wire, 0.25 mm², YE 0.2 m W1
|
||||
|
||||
|
@ -4,7 +4,7 @@ graph {
|
||||
graph [bgcolor=white fontname=arial nodesep=0.33 rankdir=LR ranksep=2]
|
||||
node [fillcolor=white fontname=arial shape=record style=filled]
|
||||
edge [fontname=arial style=bold]
|
||||
F1 [label=<
|
||||
_F1 [label=<
|
||||
|
||||
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" CELLPADDING="2"><TR>
|
||||
<TD PORT="p1l"> Crimp ferrule </TD>
|
||||
@ -14,7 +14,7 @@ graph {
|
||||
|
||||
|
||||
> margin=0 orientation=180 shape=none style=filled]
|
||||
F2 [label=<
|
||||
_F2 [label=<
|
||||
|
||||
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" CELLPADDING="2"><TR>
|
||||
<TD PORT="p1l"> Crimp ferrule </TD>
|
||||
@ -24,7 +24,7 @@ graph {
|
||||
|
||||
|
||||
> margin=0 orientation=180 shape=none style=filled]
|
||||
F3 [label=<
|
||||
_F3 [label=<
|
||||
|
||||
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" CELLPADDING="2"><TR>
|
||||
<TD PORT="p1l"> Crimp ferrule </TD>
|
||||
@ -34,7 +34,7 @@ graph {
|
||||
|
||||
|
||||
> margin=0 orientation=180 shape=none style=filled]
|
||||
F4 [label=<
|
||||
_F4 [label=<
|
||||
|
||||
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" CELLPADDING="2"><TR>
|
||||
<TD PORT="p1l"> Crimp ferrule </TD>
|
||||
@ -44,7 +44,7 @@ graph {
|
||||
|
||||
|
||||
> margin=0 orientation=180 shape=none style=filled]
|
||||
F5 [label=<
|
||||
_F5 [label=<
|
||||
|
||||
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" CELLPADDING="2"><TR>
|
||||
<TD PORT="p1l"> Crimp ferrule </TD>
|
||||
@ -54,7 +54,7 @@ graph {
|
||||
|
||||
|
||||
> margin=0 orientation=180 shape=none style=filled]
|
||||
F6 [label=<
|
||||
_F6 [label=<
|
||||
|
||||
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" CELLPADDING="2"><TR>
|
||||
<TD PORT="p1l"> Crimp ferrule </TD>
|
||||
@ -64,7 +64,7 @@ graph {
|
||||
|
||||
|
||||
> margin=0 orientation=180 shape=none style=filled]
|
||||
F7 [label=<
|
||||
_F7 [label=<
|
||||
|
||||
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" CELLPADDING="2"><TR>
|
||||
<TD PORT="p1l"> </TD>
|
||||
@ -74,7 +74,7 @@ graph {
|
||||
|
||||
|
||||
> margin=0 orientation=0 shape=none style=filled]
|
||||
F8 [label=<
|
||||
_F8 [label=<
|
||||
|
||||
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" CELLPADDING="2"><TR>
|
||||
<TD PORT="p1l"> </TD>
|
||||
@ -84,7 +84,7 @@ graph {
|
||||
|
||||
|
||||
> margin=0 orientation=0 shape=none style=filled]
|
||||
F9 [label=<
|
||||
_F9 [label=<
|
||||
|
||||
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" CELLPADDING="2"><TR>
|
||||
<TD PORT="p1l"> </TD>
|
||||
@ -94,7 +94,7 @@ graph {
|
||||
|
||||
|
||||
> margin=0 orientation=0 shape=none style=filled]
|
||||
F10 [label=<
|
||||
_F10 [label=<
|
||||
|
||||
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" CELLPADDING="2"><TR>
|
||||
<TD PORT="p1l"> </TD>
|
||||
@ -104,7 +104,7 @@ graph {
|
||||
|
||||
|
||||
> margin=0 orientation=0 shape=none style=filled]
|
||||
F11 [label=<
|
||||
_F11 [label=<
|
||||
|
||||
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" CELLPADDING="2"><TR>
|
||||
<TD PORT="p1l"> </TD>
|
||||
@ -114,7 +114,7 @@ graph {
|
||||
|
||||
|
||||
> margin=0 orientation=0 shape=none style=filled]
|
||||
F12 [label=<
|
||||
_F12 [label=<
|
||||
|
||||
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" CELLPADDING="2"><TR>
|
||||
<TD PORT="p1l"> </TD>
|
||||
@ -125,28 +125,28 @@ graph {
|
||||
|
||||
> margin=0 orientation=0 shape=none style=filled]
|
||||
edge [color="#000000:#666600:#000000"]
|
||||
F1:e -- W1:w1:w
|
||||
_F1:e -- W1:w1:w
|
||||
edge [color="#000000:#ff0000:#000000"]
|
||||
F2:e -- W1:w2:w
|
||||
_F2:e -- W1:w2:w
|
||||
edge [color="#000000:#ff8000:#000000"]
|
||||
F3:e -- W1:w3:w
|
||||
_F3:e -- W1:w3:w
|
||||
edge [color="#000000:#ffff00:#000000"]
|
||||
F4:e -- W1:w4:w
|
||||
_F4:e -- W1:w4:w
|
||||
edge [color="#000000:#00ff00:#000000"]
|
||||
F5:e -- W1:w5:w
|
||||
_F5:e -- W1:w5:w
|
||||
edge [color="#000000:#0066ff:#000000"]
|
||||
F6:e -- W1:w6:w
|
||||
_F6:e -- W1:w6:w
|
||||
edge [color="#000000:#0066ff:#000000"]
|
||||
W1:w6:e -- F7:w
|
||||
W1:w6:e -- _F7:w
|
||||
edge [color="#000000:#00ff00:#000000"]
|
||||
W1:w5:e -- F8:w
|
||||
W1:w5:e -- _F8:w
|
||||
edge [color="#000000:#ffff00:#000000"]
|
||||
W1:w4:e -- F9:w
|
||||
W1:w4:e -- _F9:w
|
||||
edge [color="#000000:#ff8000:#000000"]
|
||||
W1:w3:e -- F10:w
|
||||
W1:w3:e -- _F10:w
|
||||
edge [color="#000000:#ff0000:#000000"]
|
||||
W1:w2:e -- F11:w
|
||||
W1:w2:e -- _F11:w
|
||||
edge [color="#000000:#666600:#000000"]
|
||||
W1:w1:e -- F12:w
|
||||
W1:w1:e -- _F12:w
|
||||
W1 [label=<<table border="0" cellspacing="0" cellpadding="0"><tr><td><table border="0" cellspacing="0" cellpadding="3" cellborder="1"><tr><td colspan="3">W1</td></tr><tr><td>6x</td><td>0.25 mm² (24 AWG)</td><td>0.2 m</td></tr></table></td></tr><tr><td> </td></tr><tr><td><table border="0" cellspacing="0" cellborder="0"><tr><td></td><td>BN</td><td></td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#666600" border="2" sides="tb" port="w1"></td></tr><tr><td></td><td>RD</td><td></td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#ff0000" border="2" sides="tb" port="w2"></td></tr><tr><td></td><td>OG</td><td></td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#ff8000" border="2" sides="tb" port="w3"></td></tr><tr><td></td><td>YE</td><td></td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#ffff00" border="2" sides="tb" port="w4"></td></tr><tr><td></td><td>GN</td><td></td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#00ff00" border="2" sides="tb" port="w5"></td></tr><tr><td></td><td>BU</td><td></td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#0066ff" border="2" sides="tb" port="w6"></td></tr><tr><td> </td></tr></table></td></tr></table>> fillcolor=white margin=0 shape=box style="filled,dashed"]
|
||||
}
|
||||
|
||||
@ -8,9 +8,9 @@
|
||||
viewBox="0.00 0.00 712.00 344.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 340)">
|
||||
<polygon fill="white" stroke="transparent" points="-4,4 -4,-340 708,-340 708,4 -4,4"/>
|
||||
<!-- F1 -->
|
||||
<!-- _F1 -->
|
||||
<g id="node1" class="node">
|
||||
<title>F1</title>
|
||||
<title>_F1</title>
|
||||
<polygon fill="white" stroke="transparent" points="0,-300 109,-300 109,-336 0,-336 0,-300"/>
|
||||
<text text-anchor="start" x="3.5" y="-313.8" font-family="arial" font-size="14.00"> Crimp ferrule  </text>
|
||||
<text text-anchor="start" x="98.5" y="-313.8" font-family="arial" font-size="14.00">  </text>
|
||||
@ -55,178 +55,178 @@
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="450,-107 254,-107 "/>
|
||||
<text text-anchor="start" x="281.5" y="-88.8" font-family="arial" font-size="14.00"> </text>
|
||||
</g>
|
||||
<!-- F1--W1 -->
|
||||
<!-- _F1--W1 -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>F1:e--W1:w</title>
|
||||
<title>_F1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M109,-316C182.01,-318.14 176,-230.14 253,-228"/>
|
||||
<path fill="none" stroke="#666600" stroke-width="2" d="M109,-318C184,-318 178,-230 253,-230"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M109,-320C186,-317.86 179.99,-229.86 253,-232"/>
|
||||
</g>
|
||||
<!-- F2 -->
|
||||
<!-- _F2 -->
|
||||
<g id="node2" class="node">
|
||||
<title>F2</title>
|
||||
<title>_F2</title>
|
||||
<polygon fill="white" stroke="transparent" points="0,-240 109,-240 109,-276 0,-276 0,-240"/>
|
||||
<text text-anchor="start" x="3.5" y="-253.8" font-family="arial" font-size="14.00"> Crimp ferrule  </text>
|
||||
<text text-anchor="start" x="98.5" y="-253.8" font-family="arial" font-size="14.00">  </text>
|
||||
<polygon fill="none" stroke="black" points="0,-247.5 0,-268.5 109,-268.5 109,-247.5 0,-247.5"/>
|
||||
</g>
|
||||
<!-- F2--W1 -->
|
||||
<!-- _F2--W1 -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>F2:e--W1:w</title>
|
||||
<title>_F2:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M109,-256C175.22,-257.72 182.82,-204.72 253,-203"/>
|
||||
<path fill="none" stroke="#ff0000" stroke-width="2" d="M109,-258C177.2,-258 184.8,-205 253,-205"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M109,-260C179.18,-258.28 186.78,-205.28 253,-207"/>
|
||||
</g>
|
||||
<!-- F3 -->
|
||||
<!-- _F3 -->
|
||||
<g id="node3" class="node">
|
||||
<title>F3</title>
|
||||
<title>_F3</title>
|
||||
<polygon fill="white" stroke="transparent" points="0,-180 109,-180 109,-216 0,-216 0,-180"/>
|
||||
<text text-anchor="start" x="3.5" y="-193.8" font-family="arial" font-size="14.00"> Crimp ferrule  </text>
|
||||
<text text-anchor="start" x="98.5" y="-193.8" font-family="arial" font-size="14.00">  </text>
|
||||
<polygon fill="none" stroke="black" points="0,-187.5 0,-208.5 109,-208.5 109,-187.5 0,-187.5"/>
|
||||
</g>
|
||||
<!-- F3--W1 -->
|
||||
<!-- _F3--W1 -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>F3:e--W1:w</title>
|
||||
<title>_F3:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M109,-196C171.96,-196.72 186.97,-178.72 253,-178"/>
|
||||
<path fill="none" stroke="#ff8000" stroke-width="2" d="M109,-198C173.5,-198 188.5,-180 253,-180"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M109,-200C175.03,-199.28 190.04,-181.28 253,-182"/>
|
||||
</g>
|
||||
<!-- F4 -->
|
||||
<!-- _F4 -->
|
||||
<g id="node4" class="node">
|
||||
<title>F4</title>
|
||||
<title>_F4</title>
|
||||
<polygon fill="white" stroke="transparent" points="0,-120 109,-120 109,-156 0,-156 0,-120"/>
|
||||
<text text-anchor="start" x="3.5" y="-133.8" font-family="arial" font-size="14.00"> Crimp ferrule  </text>
|
||||
<text text-anchor="start" x="98.5" y="-133.8" font-family="arial" font-size="14.00">  </text>
|
||||
<polygon fill="none" stroke="black" points="0,-127.5 0,-148.5 109,-148.5 109,-127.5 0,-127.5"/>
|
||||
</g>
|
||||
<!-- F4--W1 -->
|
||||
<!-- _F4--W1 -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>F4:e--W1:w</title>
|
||||
<title>_F4:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M109,-136C174.94,-136.67 190.05,-153.67 253,-153"/>
|
||||
<path fill="none" stroke="#ffff00" stroke-width="2" d="M109,-138C173.44,-138 188.56,-155 253,-155"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M109,-140C171.95,-139.33 187.06,-156.33 253,-157"/>
|
||||
</g>
|
||||
<!-- F5 -->
|
||||
<!-- _F5 -->
|
||||
<g id="node5" class="node">
|
||||
<title>F5</title>
|
||||
<title>_F5</title>
|
||||
<polygon fill="white" stroke="transparent" points="0,-60 109,-60 109,-96 0,-96 0,-60"/>
|
||||
<text text-anchor="start" x="3.5" y="-73.8" font-family="arial" font-size="14.00"> Crimp ferrule  </text>
|
||||
<text text-anchor="start" x="98.5" y="-73.8" font-family="arial" font-size="14.00">  </text>
|
||||
<polygon fill="none" stroke="black" points="0,-67.5 0,-88.5 109,-88.5 109,-67.5 0,-67.5"/>
|
||||
</g>
|
||||
<!-- F5--W1 -->
|
||||
<!-- _F5--W1 -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>F5:e--W1:w</title>
|
||||
<title>_F5:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M109,-76C179.02,-77.7 186.93,-129.7 253,-128"/>
|
||||
<path fill="none" stroke="#00ff00" stroke-width="2" d="M109,-78C177.05,-78 184.95,-130 253,-130"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M109,-80C175.07,-78.3 182.98,-130.3 253,-132"/>
|
||||
</g>
|
||||
<!-- F6 -->
|
||||
<!-- _F6 -->
|
||||
<g id="node6" class="node">
|
||||
<title>F6</title>
|
||||
<title>_F6</title>
|
||||
<polygon fill="white" stroke="transparent" points="0,0 109,0 109,-36 0,-36 0,0"/>
|
||||
<text text-anchor="start" x="3.5" y="-13.8" font-family="arial" font-size="14.00"> Crimp ferrule  </text>
|
||||
<text text-anchor="start" x="98.5" y="-13.8" font-family="arial" font-size="14.00">  </text>
|
||||
<polygon fill="none" stroke="black" points="0,-7.5 0,-28.5 109,-28.5 109,-7.5 0,-7.5"/>
|
||||
</g>
|
||||
<!-- F6--W1 -->
|
||||
<!-- _F6--W1 -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>F6:e--W1:w</title>
|
||||
<title>_F6:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M109,-16C185.77,-18.13 180.22,-105.13 253,-103"/>
|
||||
<path fill="none" stroke="#0066ff" stroke-width="2" d="M109,-18C183.77,-18 178.23,-105 253,-105"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M109,-20C181.78,-17.87 176.23,-104.87 253,-107"/>
|
||||
</g>
|
||||
<!-- F7 -->
|
||||
<!-- _F7 -->
|
||||
<g id="node7" class="node">
|
||||
<title>F7</title>
|
||||
<title>_F7</title>
|
||||
<polygon fill="white" stroke="transparent" points="704,-36 595,-36 595,0 704,0 704,-36"/>
|
||||
<text text-anchor="start" x="598.5" y="-13.8" font-family="arial" font-size="14.00">  </text>
|
||||
<text text-anchor="start" x="610.5" y="-13.8" font-family="arial" font-size="14.00"> Crimp ferrule  </text>
|
||||
<polygon fill="none" stroke="black" points="595,-7.5 595,-28.5 704,-28.5 704,-7.5 595,-7.5"/>
|
||||
</g>
|
||||
<!-- F8 -->
|
||||
<!-- _F8 -->
|
||||
<g id="node8" class="node">
|
||||
<title>F8</title>
|
||||
<title>_F8</title>
|
||||
<polygon fill="white" stroke="transparent" points="704,-96 595,-96 595,-60 704,-60 704,-96"/>
|
||||
<text text-anchor="start" x="598.5" y="-73.8" font-family="arial" font-size="14.00">  </text>
|
||||
<text text-anchor="start" x="610.5" y="-73.8" font-family="arial" font-size="14.00"> Crimp ferrule  </text>
|
||||
<polygon fill="none" stroke="black" points="595,-67.5 595,-88.5 704,-88.5 704,-67.5 595,-67.5"/>
|
||||
</g>
|
||||
<!-- F9 -->
|
||||
<!-- _F9 -->
|
||||
<g id="node9" class="node">
|
||||
<title>F9</title>
|
||||
<title>_F9</title>
|
||||
<polygon fill="white" stroke="transparent" points="704,-156 595,-156 595,-120 704,-120 704,-156"/>
|
||||
<text text-anchor="start" x="598.5" y="-133.8" font-family="arial" font-size="14.00">  </text>
|
||||
<text text-anchor="start" x="610.5" y="-133.8" font-family="arial" font-size="14.00"> Crimp ferrule  </text>
|
||||
<polygon fill="none" stroke="black" points="595,-127.5 595,-148.5 704,-148.5 704,-127.5 595,-127.5"/>
|
||||
</g>
|
||||
<!-- F10 -->
|
||||
<!-- _F10 -->
|
||||
<g id="node10" class="node">
|
||||
<title>F10</title>
|
||||
<title>_F10</title>
|
||||
<polygon fill="white" stroke="transparent" points="704,-216 595,-216 595,-180 704,-180 704,-216"/>
|
||||
<text text-anchor="start" x="598.5" y="-193.8" font-family="arial" font-size="14.00">  </text>
|
||||
<text text-anchor="start" x="610.5" y="-193.8" font-family="arial" font-size="14.00"> Crimp ferrule  </text>
|
||||
<polygon fill="none" stroke="black" points="595,-187.5 595,-208.5 704,-208.5 704,-187.5 595,-187.5"/>
|
||||
</g>
|
||||
<!-- F11 -->
|
||||
<!-- _F11 -->
|
||||
<g id="node11" class="node">
|
||||
<title>F11</title>
|
||||
<title>_F11</title>
|
||||
<polygon fill="white" stroke="transparent" points="704,-276 595,-276 595,-240 704,-240 704,-276"/>
|
||||
<text text-anchor="start" x="598.5" y="-253.8" font-family="arial" font-size="14.00">  </text>
|
||||
<text text-anchor="start" x="610.5" y="-253.8" font-family="arial" font-size="14.00"> Crimp ferrule  </text>
|
||||
<polygon fill="none" stroke="black" points="595,-247.5 595,-268.5 704,-268.5 704,-247.5 595,-247.5"/>
|
||||
</g>
|
||||
<!-- F12 -->
|
||||
<!-- _F12 -->
|
||||
<g id="node12" class="node">
|
||||
<title>F12</title>
|
||||
<title>_F12</title>
|
||||
<polygon fill="white" stroke="transparent" points="704,-336 595,-336 595,-300 704,-300 704,-336"/>
|
||||
<text text-anchor="start" x="598.5" y="-313.8" font-family="arial" font-size="14.00">  </text>
|
||||
<text text-anchor="start" x="610.5" y="-313.8" font-family="arial" font-size="14.00"> Crimp ferrule  </text>
|
||||
<polygon fill="none" stroke="black" points="595,-307.5 595,-328.5 704,-328.5 704,-307.5 595,-307.5"/>
|
||||
</g>
|
||||
<!-- W1--F7 -->
|
||||
<!-- W1--_F7 -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>W1:e--F7:w</title>
|
||||
<title>W1:e--_F7:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M451,-103C523.78,-105.13 518.23,-18.13 595,-16"/>
|
||||
<path fill="none" stroke="#0066ff" stroke-width="2" d="M451,-105C525.77,-105 520.23,-18 595,-18"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M451,-107C527.77,-104.87 522.22,-17.87 595,-20"/>
|
||||
</g>
|
||||
<!-- W1--F8 -->
|
||||
<!-- W1--_F8 -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>W1:e--F8:w</title>
|
||||
<title>W1:e--_F8:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M451,-128C517.07,-129.7 524.98,-77.7 595,-76"/>
|
||||
<path fill="none" stroke="#00ff00" stroke-width="2" d="M451,-130C519.05,-130 526.95,-78 595,-78"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M451,-132C521.02,-130.3 528.93,-78.3 595,-80"/>
|
||||
</g>
|
||||
<!-- W1--F9 -->
|
||||
<!-- W1--_F9 -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>W1:e--F9:w</title>
|
||||
<title>W1:e--_F9:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M451,-153C513.95,-153.67 529.06,-136.67 595,-136"/>
|
||||
<path fill="none" stroke="#ffff00" stroke-width="2" d="M451,-155C515.44,-155 530.56,-138 595,-138"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M451,-157C516.94,-156.33 532.05,-139.33 595,-140"/>
|
||||
</g>
|
||||
<!-- W1--F10 -->
|
||||
<!-- W1--_F10 -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>W1:e--F10:w</title>
|
||||
<title>W1:e--_F10:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M451,-178C517.03,-178.72 532.04,-196.72 595,-196"/>
|
||||
<path fill="none" stroke="#ff8000" stroke-width="2" d="M451,-180C515.5,-180 530.5,-198 595,-198"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M451,-182C513.96,-181.28 528.97,-199.28 595,-200"/>
|
||||
</g>
|
||||
<!-- W1--F11 -->
|
||||
<!-- W1--_F11 -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>W1:e--F11:w</title>
|
||||
<title>W1:e--_F11:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M451,-203C521.18,-204.72 528.78,-257.72 595,-256"/>
|
||||
<path fill="none" stroke="#ff0000" stroke-width="2" d="M451,-205C519.2,-205 526.8,-258 595,-258"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M451,-207C517.22,-205.28 524.82,-258.28 595,-260"/>
|
||||
</g>
|
||||
<!-- W1--F12 -->
|
||||
<!-- W1--_F12 -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>W1:e--F12:w</title>
|
||||
<title>W1:e--_F12:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M451,-228C528,-230.14 521.99,-318.14 595,-316"/>
|
||||
<path fill="none" stroke="#666600" stroke-width="2" d="M451,-230C526,-230 520,-318 595,-318"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M451,-232C524.01,-229.86 518,-317.86 595,-320"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<h1>Bill of Materials</h1><table style="border:1px solid #000000; font-size: 14pt; border-spacing: 0px"><tr><th align="left" style="border:1px solid #000000; padding: 8px">Item</th><th align="left" style="border:1px solid #000000; padding: 8px">Qty</th><th align="left" style="border:1px solid #000000; padding: 8px">Unit</th><th align="left" style="border:1px solid #000000; padding: 8px">Designators</th></tr><tr><td style="border:1px solid #000000; padding: 4px">Crimp ferrule</td><td align="right" style="border:1px solid #000000; padding: 4px">12</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px"></td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire 0.25 mm² BN</td><td align="right" style="border:1px solid #000000; padding: 4px">0.2</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire 0.25 mm² BU</td><td align="right" style="border:1px solid #000000; padding: 4px">0.2</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire 0.25 mm² GN</td><td align="right" style="border:1px solid #000000; padding: 4px">0.2</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire 0.25 mm² OG</td><td align="right" style="border:1px solid #000000; padding: 4px">0.2</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire 0.25 mm² RD</td><td align="right" style="border:1px solid #000000; padding: 4px">0.2</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire 0.25 mm² YE</td><td align="right" style="border:1px solid #000000; padding: 4px">0.2</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1</td></tr></table></body></html>
|
||||
<h1>Bill of Materials</h1><table style="border:1px solid #000000; font-size: 14pt; border-spacing: 0px"><tr><th align="left" style="border:1px solid #000000; padding: 8px">Item</th><th align="left" style="border:1px solid #000000; padding: 8px">Qty</th><th align="left" style="border:1px solid #000000; padding: 8px">Unit</th><th align="left" style="border:1px solid #000000; padding: 8px">Designators</th></tr><tr><td style="border:1px solid #000000; padding: 4px">Connector, Crimp ferrule</td><td align="right" style="border:1px solid #000000; padding: 4px">12</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px"></td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire, 0.25 mm², BN</td><td align="right" style="border:1px solid #000000; padding: 4px">0.2</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire, 0.25 mm², BU</td><td align="right" style="border:1px solid #000000; padding: 4px">0.2</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire, 0.25 mm², GN</td><td align="right" style="border:1px solid #000000; padding: 4px">0.2</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire, 0.25 mm², OG</td><td align="right" style="border:1px solid #000000; padding: 4px">0.2</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire, 0.25 mm², RD</td><td align="right" style="border:1px solid #000000; padding: 4px">0.2</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire, 0.25 mm², YE</td><td align="right" style="border:1px solid #000000; padding: 4px">0.2</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1</td></tr></table></body></html>
|
||||
@ -8,9 +8,9 @@
|
||||
viewBox="0.00 0.00 712.00 344.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 340)">
|
||||
<polygon fill="white" stroke="transparent" points="-4,4 -4,-340 708,-340 708,4 -4,4"/>
|
||||
<!-- F1 -->
|
||||
<!-- _F1 -->
|
||||
<g id="node1" class="node">
|
||||
<title>F1</title>
|
||||
<title>_F1</title>
|
||||
<polygon fill="white" stroke="transparent" points="0,-300 109,-300 109,-336 0,-336 0,-300"/>
|
||||
<text text-anchor="start" x="3.5" y="-313.8" font-family="arial" font-size="14.00"> Crimp ferrule  </text>
|
||||
<text text-anchor="start" x="98.5" y="-313.8" font-family="arial" font-size="14.00">  </text>
|
||||
@ -55,174 +55,174 @@
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="450,-107 254,-107 "/>
|
||||
<text text-anchor="start" x="281.5" y="-88.8" font-family="arial" font-size="14.00"> </text>
|
||||
</g>
|
||||
<!-- F1--W1 -->
|
||||
<!-- _F1--W1 -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>F1:e--W1:w</title>
|
||||
<title>_F1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M109,-316C182.01,-318.14 176,-230.14 253,-228"/>
|
||||
<path fill="none" stroke="#666600" stroke-width="2" d="M109,-318C184,-318 178,-230 253,-230"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M109,-320C186,-317.86 179.99,-229.86 253,-232"/>
|
||||
</g>
|
||||
<!-- F2 -->
|
||||
<!-- _F2 -->
|
||||
<g id="node2" class="node">
|
||||
<title>F2</title>
|
||||
<title>_F2</title>
|
||||
<polygon fill="white" stroke="transparent" points="0,-240 109,-240 109,-276 0,-276 0,-240"/>
|
||||
<text text-anchor="start" x="3.5" y="-253.8" font-family="arial" font-size="14.00"> Crimp ferrule  </text>
|
||||
<text text-anchor="start" x="98.5" y="-253.8" font-family="arial" font-size="14.00">  </text>
|
||||
<polygon fill="none" stroke="black" points="0,-247.5 0,-268.5 109,-268.5 109,-247.5 0,-247.5"/>
|
||||
</g>
|
||||
<!-- F2--W1 -->
|
||||
<!-- _F2--W1 -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>F2:e--W1:w</title>
|
||||
<title>_F2:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M109,-256C175.22,-257.72 182.82,-204.72 253,-203"/>
|
||||
<path fill="none" stroke="#ff0000" stroke-width="2" d="M109,-258C177.2,-258 184.8,-205 253,-205"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M109,-260C179.18,-258.28 186.78,-205.28 253,-207"/>
|
||||
</g>
|
||||
<!-- F3 -->
|
||||
<!-- _F3 -->
|
||||
<g id="node3" class="node">
|
||||
<title>F3</title>
|
||||
<title>_F3</title>
|
||||
<polygon fill="white" stroke="transparent" points="0,-180 109,-180 109,-216 0,-216 0,-180"/>
|
||||
<text text-anchor="start" x="3.5" y="-193.8" font-family="arial" font-size="14.00"> Crimp ferrule  </text>
|
||||
<text text-anchor="start" x="98.5" y="-193.8" font-family="arial" font-size="14.00">  </text>
|
||||
<polygon fill="none" stroke="black" points="0,-187.5 0,-208.5 109,-208.5 109,-187.5 0,-187.5"/>
|
||||
</g>
|
||||
<!-- F3--W1 -->
|
||||
<!-- _F3--W1 -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>F3:e--W1:w</title>
|
||||
<title>_F3:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M109,-196C171.96,-196.72 186.97,-178.72 253,-178"/>
|
||||
<path fill="none" stroke="#ff8000" stroke-width="2" d="M109,-198C173.5,-198 188.5,-180 253,-180"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M109,-200C175.03,-199.28 190.04,-181.28 253,-182"/>
|
||||
</g>
|
||||
<!-- F4 -->
|
||||
<!-- _F4 -->
|
||||
<g id="node4" class="node">
|
||||
<title>F4</title>
|
||||
<title>_F4</title>
|
||||
<polygon fill="white" stroke="transparent" points="0,-120 109,-120 109,-156 0,-156 0,-120"/>
|
||||
<text text-anchor="start" x="3.5" y="-133.8" font-family="arial" font-size="14.00"> Crimp ferrule  </text>
|
||||
<text text-anchor="start" x="98.5" y="-133.8" font-family="arial" font-size="14.00">  </text>
|
||||
<polygon fill="none" stroke="black" points="0,-127.5 0,-148.5 109,-148.5 109,-127.5 0,-127.5"/>
|
||||
</g>
|
||||
<!-- F4--W1 -->
|
||||
<!-- _F4--W1 -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>F4:e--W1:w</title>
|
||||
<title>_F4:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M109,-136C174.94,-136.67 190.05,-153.67 253,-153"/>
|
||||
<path fill="none" stroke="#ffff00" stroke-width="2" d="M109,-138C173.44,-138 188.56,-155 253,-155"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M109,-140C171.95,-139.33 187.06,-156.33 253,-157"/>
|
||||
</g>
|
||||
<!-- F5 -->
|
||||
<!-- _F5 -->
|
||||
<g id="node5" class="node">
|
||||
<title>F5</title>
|
||||
<title>_F5</title>
|
||||
<polygon fill="white" stroke="transparent" points="0,-60 109,-60 109,-96 0,-96 0,-60"/>
|
||||
<text text-anchor="start" x="3.5" y="-73.8" font-family="arial" font-size="14.00"> Crimp ferrule  </text>
|
||||
<text text-anchor="start" x="98.5" y="-73.8" font-family="arial" font-size="14.00">  </text>
|
||||
<polygon fill="none" stroke="black" points="0,-67.5 0,-88.5 109,-88.5 109,-67.5 0,-67.5"/>
|
||||
</g>
|
||||
<!-- F5--W1 -->
|
||||
<!-- _F5--W1 -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>F5:e--W1:w</title>
|
||||
<title>_F5:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M109,-76C179.02,-77.7 186.93,-129.7 253,-128"/>
|
||||
<path fill="none" stroke="#00ff00" stroke-width="2" d="M109,-78C177.05,-78 184.95,-130 253,-130"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M109,-80C175.07,-78.3 182.98,-130.3 253,-132"/>
|
||||
</g>
|
||||
<!-- F6 -->
|
||||
<!-- _F6 -->
|
||||
<g id="node6" class="node">
|
||||
<title>F6</title>
|
||||
<title>_F6</title>
|
||||
<polygon fill="white" stroke="transparent" points="0,0 109,0 109,-36 0,-36 0,0"/>
|
||||
<text text-anchor="start" x="3.5" y="-13.8" font-family="arial" font-size="14.00"> Crimp ferrule  </text>
|
||||
<text text-anchor="start" x="98.5" y="-13.8" font-family="arial" font-size="14.00">  </text>
|
||||
<polygon fill="none" stroke="black" points="0,-7.5 0,-28.5 109,-28.5 109,-7.5 0,-7.5"/>
|
||||
</g>
|
||||
<!-- F6--W1 -->
|
||||
<!-- _F6--W1 -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>F6:e--W1:w</title>
|
||||
<title>_F6:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M109,-16C185.77,-18.13 180.22,-105.13 253,-103"/>
|
||||
<path fill="none" stroke="#0066ff" stroke-width="2" d="M109,-18C183.77,-18 178.23,-105 253,-105"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M109,-20C181.78,-17.87 176.23,-104.87 253,-107"/>
|
||||
</g>
|
||||
<!-- F7 -->
|
||||
<!-- _F7 -->
|
||||
<g id="node7" class="node">
|
||||
<title>F7</title>
|
||||
<title>_F7</title>
|
||||
<polygon fill="white" stroke="transparent" points="704,-36 595,-36 595,0 704,0 704,-36"/>
|
||||
<text text-anchor="start" x="598.5" y="-13.8" font-family="arial" font-size="14.00">  </text>
|
||||
<text text-anchor="start" x="610.5" y="-13.8" font-family="arial" font-size="14.00"> Crimp ferrule  </text>
|
||||
<polygon fill="none" stroke="black" points="595,-7.5 595,-28.5 704,-28.5 704,-7.5 595,-7.5"/>
|
||||
</g>
|
||||
<!-- F8 -->
|
||||
<!-- _F8 -->
|
||||
<g id="node8" class="node">
|
||||
<title>F8</title>
|
||||
<title>_F8</title>
|
||||
<polygon fill="white" stroke="transparent" points="704,-96 595,-96 595,-60 704,-60 704,-96"/>
|
||||
<text text-anchor="start" x="598.5" y="-73.8" font-family="arial" font-size="14.00">  </text>
|
||||
<text text-anchor="start" x="610.5" y="-73.8" font-family="arial" font-size="14.00"> Crimp ferrule  </text>
|
||||
<polygon fill="none" stroke="black" points="595,-67.5 595,-88.5 704,-88.5 704,-67.5 595,-67.5"/>
|
||||
</g>
|
||||
<!-- F9 -->
|
||||
<!-- _F9 -->
|
||||
<g id="node9" class="node">
|
||||
<title>F9</title>
|
||||
<title>_F9</title>
|
||||
<polygon fill="white" stroke="transparent" points="704,-156 595,-156 595,-120 704,-120 704,-156"/>
|
||||
<text text-anchor="start" x="598.5" y="-133.8" font-family="arial" font-size="14.00">  </text>
|
||||
<text text-anchor="start" x="610.5" y="-133.8" font-family="arial" font-size="14.00"> Crimp ferrule  </text>
|
||||
<polygon fill="none" stroke="black" points="595,-127.5 595,-148.5 704,-148.5 704,-127.5 595,-127.5"/>
|
||||
</g>
|
||||
<!-- F10 -->
|
||||
<!-- _F10 -->
|
||||
<g id="node10" class="node">
|
||||
<title>F10</title>
|
||||
<title>_F10</title>
|
||||
<polygon fill="white" stroke="transparent" points="704,-216 595,-216 595,-180 704,-180 704,-216"/>
|
||||
<text text-anchor="start" x="598.5" y="-193.8" font-family="arial" font-size="14.00">  </text>
|
||||
<text text-anchor="start" x="610.5" y="-193.8" font-family="arial" font-size="14.00"> Crimp ferrule  </text>
|
||||
<polygon fill="none" stroke="black" points="595,-187.5 595,-208.5 704,-208.5 704,-187.5 595,-187.5"/>
|
||||
</g>
|
||||
<!-- F11 -->
|
||||
<!-- _F11 -->
|
||||
<g id="node11" class="node">
|
||||
<title>F11</title>
|
||||
<title>_F11</title>
|
||||
<polygon fill="white" stroke="transparent" points="704,-276 595,-276 595,-240 704,-240 704,-276"/>
|
||||
<text text-anchor="start" x="598.5" y="-253.8" font-family="arial" font-size="14.00">  </text>
|
||||
<text text-anchor="start" x="610.5" y="-253.8" font-family="arial" font-size="14.00"> Crimp ferrule  </text>
|
||||
<polygon fill="none" stroke="black" points="595,-247.5 595,-268.5 704,-268.5 704,-247.5 595,-247.5"/>
|
||||
</g>
|
||||
<!-- F12 -->
|
||||
<!-- _F12 -->
|
||||
<g id="node12" class="node">
|
||||
<title>F12</title>
|
||||
<title>_F12</title>
|
||||
<polygon fill="white" stroke="transparent" points="704,-336 595,-336 595,-300 704,-300 704,-336"/>
|
||||
<text text-anchor="start" x="598.5" y="-313.8" font-family="arial" font-size="14.00">  </text>
|
||||
<text text-anchor="start" x="610.5" y="-313.8" font-family="arial" font-size="14.00"> Crimp ferrule  </text>
|
||||
<polygon fill="none" stroke="black" points="595,-307.5 595,-328.5 704,-328.5 704,-307.5 595,-307.5"/>
|
||||
</g>
|
||||
<!-- W1--F7 -->
|
||||
<!-- W1--_F7 -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>W1:e--F7:w</title>
|
||||
<title>W1:e--_F7:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M451,-103C523.78,-105.13 518.23,-18.13 595,-16"/>
|
||||
<path fill="none" stroke="#0066ff" stroke-width="2" d="M451,-105C525.77,-105 520.23,-18 595,-18"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M451,-107C527.77,-104.87 522.22,-17.87 595,-20"/>
|
||||
</g>
|
||||
<!-- W1--F8 -->
|
||||
<!-- W1--_F8 -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>W1:e--F8:w</title>
|
||||
<title>W1:e--_F8:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M451,-128C517.07,-129.7 524.98,-77.7 595,-76"/>
|
||||
<path fill="none" stroke="#00ff00" stroke-width="2" d="M451,-130C519.05,-130 526.95,-78 595,-78"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M451,-132C521.02,-130.3 528.93,-78.3 595,-80"/>
|
||||
</g>
|
||||
<!-- W1--F9 -->
|
||||
<!-- W1--_F9 -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>W1:e--F9:w</title>
|
||||
<title>W1:e--_F9:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M451,-153C513.95,-153.67 529.06,-136.67 595,-136"/>
|
||||
<path fill="none" stroke="#ffff00" stroke-width="2" d="M451,-155C515.44,-155 530.56,-138 595,-138"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M451,-157C516.94,-156.33 532.05,-139.33 595,-140"/>
|
||||
</g>
|
||||
<!-- W1--F10 -->
|
||||
<!-- W1--_F10 -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>W1:e--F10:w</title>
|
||||
<title>W1:e--_F10:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M451,-178C517.03,-178.72 532.04,-196.72 595,-196"/>
|
||||
<path fill="none" stroke="#ff8000" stroke-width="2" d="M451,-180C515.5,-180 530.5,-198 595,-198"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M451,-182C513.96,-181.28 528.97,-199.28 595,-200"/>
|
||||
</g>
|
||||
<!-- W1--F11 -->
|
||||
<!-- W1--_F11 -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>W1:e--F11:w</title>
|
||||
<title>W1:e--_F11:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M451,-203C521.18,-204.72 528.78,-257.72 595,-256"/>
|
||||
<path fill="none" stroke="#ff0000" stroke-width="2" d="M451,-205C519.2,-205 526.8,-258 595,-258"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M451,-207C517.22,-205.28 524.82,-258.28 595,-260"/>
|
||||
</g>
|
||||
<!-- W1--F12 -->
|
||||
<!-- W1--_F12 -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>W1:e--F12:w</title>
|
||||
<title>W1:e--_F12:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M451,-228C528,-230.14 521.99,-318.14 595,-316"/>
|
||||
<path fill="none" stroke="#666600" stroke-width="2" d="M451,-230C526,-230 520,-318 595,-318"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M451,-232C524.01,-229.86 518,-317.86 595,-320"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
@ -1,6 +1,6 @@
|
||||
Item Qty Unit Designators
|
||||
Molex KK 254, female, 4 pins 3 X1, X2, X3
|
||||
Wire 0.25 mm² PK 0.4 m W1, W2
|
||||
Wire 0.25 mm² TQ 0.4 m W1, W2
|
||||
Wire 0.25 mm² VT 0.4 m W1, W2
|
||||
Wire 0.25 mm² YE 0.4 m W1, W2
|
||||
Connector, Molex KK 254, female, 4 pins 3 X1, X2, X3
|
||||
Wire, 0.25 mm², PK 0.4 m W1, W2
|
||||
Wire, 0.25 mm², TQ 0.4 m W1, W2
|
||||
Wire, 0.25 mm², VT 0.4 m W1, W2
|
||||
Wire, 0.25 mm², YE 0.4 m W1, W2
|
||||
|
||||
|
@ -292,4 +292,4 @@
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<h1>Bill of Materials</h1><table style="border:1px solid #000000; font-size: 14pt; border-spacing: 0px"><tr><th align="left" style="border:1px solid #000000; padding: 8px">Item</th><th align="left" style="border:1px solid #000000; padding: 8px">Qty</th><th align="left" style="border:1px solid #000000; padding: 8px">Unit</th><th align="left" style="border:1px solid #000000; padding: 8px">Designators</th></tr><tr><td style="border:1px solid #000000; padding: 4px">Molex KK 254, female, 4 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">3</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X1, X2, X3</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire 0.25 mm² PK</td><td align="right" style="border:1px solid #000000; padding: 4px">0.4</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1, W2</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire 0.25 mm² TQ</td><td align="right" style="border:1px solid #000000; padding: 4px">0.4</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1, W2</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire 0.25 mm² VT</td><td align="right" style="border:1px solid #000000; padding: 4px">0.4</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1, W2</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire 0.25 mm² YE</td><td align="right" style="border:1px solid #000000; padding: 4px">0.4</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1, W2</td></tr></table></body></html>
|
||||
<h1>Bill of Materials</h1><table style="border:1px solid #000000; font-size: 14pt; border-spacing: 0px"><tr><th align="left" style="border:1px solid #000000; padding: 8px">Item</th><th align="left" style="border:1px solid #000000; padding: 8px">Qty</th><th align="left" style="border:1px solid #000000; padding: 8px">Unit</th><th align="left" style="border:1px solid #000000; padding: 8px">Designators</th></tr><tr><td style="border:1px solid #000000; padding: 4px">Connector, Molex KK 254, female, 4 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">3</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X1, X2, X3</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire, 0.25 mm², PK</td><td align="right" style="border:1px solid #000000; padding: 4px">0.4</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1, W2</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire, 0.25 mm², TQ</td><td align="right" style="border:1px solid #000000; padding: 4px">0.4</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1, W2</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire, 0.25 mm², VT</td><td align="right" style="border:1px solid #000000; padding: 4px">0.4</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1, W2</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire, 0.25 mm², YE</td><td align="right" style="border:1px solid #000000; padding: 4px">0.4</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1, W2</td></tr></table></body></html>
|
||||
@ -1,6 +1,6 @@
|
||||
Item Qty Unit Designators
|
||||
Molex KK 254, female, 4 pins 6 X1, X2, X3, X4, X5, X6
|
||||
Wire 0.25 mm² PK 1.0 m W1, W2, W3, W4, W5
|
||||
Wire 0.25 mm² TQ 1.0 m W1, W2, W3, W4, W5
|
||||
Wire 0.25 mm² VT 1.0 m W1, W2, W3, W4, W5
|
||||
Wire 0.25 mm² YE 1.0 m W1, W2, W3, W4, W5
|
||||
Connector, Molex KK 254, female, 4 pins 6 X1, X2, X3, X4, X5, X6
|
||||
Wire, 0.25 mm², PK 1.0 m W1, W2, W3, W4, W5
|
||||
Wire, 0.25 mm², TQ 1.0 m W1, W2, W3, W4, W5
|
||||
Wire, 0.25 mm², VT 1.0 m W1, W2, W3, W4, W5
|
||||
Wire, 0.25 mm², YE 1.0 m W1, W2, W3, W4, W5
|
||||
|
||||
|
@ -653,4 +653,4 @@
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<h1>Bill of Materials</h1><table style="border:1px solid #000000; font-size: 14pt; border-spacing: 0px"><tr><th align="left" style="border:1px solid #000000; padding: 8px">Item</th><th align="left" style="border:1px solid #000000; padding: 8px">Qty</th><th align="left" style="border:1px solid #000000; padding: 8px">Unit</th><th align="left" style="border:1px solid #000000; padding: 8px">Designators</th></tr><tr><td style="border:1px solid #000000; padding: 4px">Molex KK 254, female, 4 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">6</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X1, X2, X3, X4, X5, X6</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire 0.25 mm² PK</td><td align="right" style="border:1px solid #000000; padding: 4px">1.0</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1, W2, W3, W4, W5</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire 0.25 mm² TQ</td><td align="right" style="border:1px solid #000000; padding: 4px">1.0</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1, W2, W3, W4, W5</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire 0.25 mm² VT</td><td align="right" style="border:1px solid #000000; padding: 4px">1.0</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1, W2, W3, W4, W5</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire 0.25 mm² YE</td><td align="right" style="border:1px solid #000000; padding: 4px">1.0</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1, W2, W3, W4, W5</td></tr></table></body></html>
|
||||
<h1>Bill of Materials</h1><table style="border:1px solid #000000; font-size: 14pt; border-spacing: 0px"><tr><th align="left" style="border:1px solid #000000; padding: 8px">Item</th><th align="left" style="border:1px solid #000000; padding: 8px">Qty</th><th align="left" style="border:1px solid #000000; padding: 8px">Unit</th><th align="left" style="border:1px solid #000000; padding: 8px">Designators</th></tr><tr><td style="border:1px solid #000000; padding: 4px">Connector, Molex KK 254, female, 4 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">6</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X1, X2, X3, X4, X5, X6</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire, 0.25 mm², PK</td><td align="right" style="border:1px solid #000000; padding: 4px">1.0</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1, W2, W3, W4, W5</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire, 0.25 mm², TQ</td><td align="right" style="border:1px solid #000000; padding: 4px">1.0</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1, W2, W3, W4, W5</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire, 0.25 mm², VT</td><td align="right" style="border:1px solid #000000; padding: 4px">1.0</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1, W2, W3, W4, W5</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Wire, 0.25 mm², YE</td><td align="right" style="border:1px solid #000000; padding: 4px">1.0</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1, W2, W3, W4, W5</td></tr></table></body></html>
|
||||
4
examples/ex07.bom.tsv
Normal file
@ -0,0 +1,4 @@
|
||||
Item Qty Unit Designators
|
||||
Connector, D-Sub, female, 9 pins 1 X2
|
||||
Connector, TE 776164-1, female, 35 pins 1 X1
|
||||
Cable, 2 x 20 AWG 1 m C1
|
||||
|
16
examples/ex07.gv
Normal file
@ -0,0 +1,16 @@
|
||||
graph {
|
||||
// Graph generated by WireViz
|
||||
// https://github.com/formatc1702/WireViz
|
||||
graph [bgcolor=white fontname=arial nodesep=0.33 rankdir=LR ranksep=2]
|
||||
node [fillcolor=white fontname=arial shape=record style=filled]
|
||||
edge [fontname=arial style=bold]
|
||||
X1 [label="X1|{TE 776164-1|female|35-pin}|{{<p5r>5|<p6r>6}}|Unconnected pins are not shown"]
|
||||
X2 [label="X2|{D-Sub|female|9-pin}|{{<p2l>2|<p7l>7}}|Unconnected pins are not shown"]
|
||||
edge [color="#000000:#ffff00:#000000"]
|
||||
X1:p5r:e -- C1:w1:w
|
||||
C1:w1:e -- X2:p7l:w
|
||||
edge [color="#000000:#00ff00:#000000"]
|
||||
X1:p6r:e -- C1:w2:w
|
||||
C1:w2:e -- X2:p2l:w
|
||||
C1 [label=<<table border="0" cellspacing="0" cellpadding="0"><tr><td><table border="0" cellspacing="0" cellpadding="3" cellborder="1"><tr><td colspan="3">C1</td></tr><tr><td>2x</td><td>20 AWG</td><td>1 m</td></tr></table></td></tr><tr><td> </td></tr><tr><td><table border="0" cellspacing="0" cellborder="0"><tr><td>X1:5</td><td>YE</td><td>X2:7</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#ffff00" border="2" sides="tb" port="w1"></td></tr><tr><td>X1:6</td><td>GN</td><td>X2:2</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#00ff00" border="2" sides="tb" port="w2"></td></tr><tr><td> </td></tr></table></td></tr></table>> fillcolor=white margin=0 shape=box style=""]
|
||||
}
|
||||
104
examples/ex07.html
Normal file
@ -0,0 +1,104 @@
|
||||
<html><body style="font-family:Arial"><h1>Diagram</h1><?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.44.0 (20200408.0750)
|
||||
-->
|
||||
<!-- Pages: 1 -->
|
||||
<svg width="837pt" height="150pt"
|
||||
viewBox="0.00 0.00 837.00 150.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 146)">
|
||||
<polygon fill="white" stroke="transparent" points="-4,4 -4,-146 833,-146 833,4 -4,4"/>
|
||||
<!-- X1 -->
|
||||
<g id="node1" class="node">
|
||||
<title>X1</title>
|
||||
<polygon fill="white" stroke="black" points="0,-0.5 0,-115.5 213,-115.5 213,-0.5 0,-0.5"/>
|
||||
<text text-anchor="middle" x="106.5" y="-100.3" font-family="arial" font-size="14.00">X1</text>
|
||||
<polyline fill="none" stroke="black" points="0,-92.5 213,-92.5 "/>
|
||||
<text text-anchor="middle" x="48.5" y="-77.3" font-family="arial" font-size="14.00">TE 776164-1</text>
|
||||
<polyline fill="none" stroke="black" points="97,-69.5 97,-92.5 "/>
|
||||
<text text-anchor="middle" x="127" y="-77.3" font-family="arial" font-size="14.00">female</text>
|
||||
<polyline fill="none" stroke="black" points="157,-69.5 157,-92.5 "/>
|
||||
<text text-anchor="middle" x="185" y="-77.3" font-family="arial" font-size="14.00">35-pin</text>
|
||||
<polyline fill="none" stroke="black" points="0,-69.5 213,-69.5 "/>
|
||||
<text text-anchor="middle" x="106.5" y="-54.3" font-family="arial" font-size="14.00">5</text>
|
||||
<polyline fill="none" stroke="black" points="0,-46.5 213,-46.5 "/>
|
||||
<text text-anchor="middle" x="106.5" y="-31.3" font-family="arial" font-size="14.00">6</text>
|
||||
<polyline fill="none" stroke="black" points="0,-23.5 213,-23.5 "/>
|
||||
<text text-anchor="middle" x="106.5" y="-8.3" font-family="arial" font-size="14.00">Unconnected pins are not shown</text>
|
||||
</g>
|
||||
<!-- C1 -->
|
||||
<g id="node3" class="node">
|
||||
<title>C1</title>
|
||||
<polygon fill="none" stroke="black" points="472,-142 357,-142 357,-12 472,-12 472,-142"/>
|
||||
<polygon fill="none" stroke="black" points="357.5,-119 357.5,-142 472.5,-142 472.5,-119 357.5,-119"/>
|
||||
<text text-anchor="start" x="406" y="-126.8" font-family="arial" font-size="14.00">C1</text>
|
||||
<polygon fill="none" stroke="black" points="357.5,-96 357.5,-119 380.5,-119 380.5,-96 357.5,-96"/>
|
||||
<text text-anchor="start" x="361.5" y="-103.8" font-family="arial" font-size="14.00">2x</text>
|
||||
<polygon fill="none" stroke="black" points="380.5,-96 380.5,-119 440.5,-119 440.5,-96 380.5,-96"/>
|
||||
<text text-anchor="start" x="384.5" y="-103.8" font-family="arial" font-size="14.00">20 AWG</text>
|
||||
<polygon fill="none" stroke="black" points="440.5,-96 440.5,-119 472.5,-119 472.5,-96 440.5,-96"/>
|
||||
<text text-anchor="start" x="444.5" y="-103.8" font-family="arial" font-size="14.00">1 m</text>
|
||||
<text text-anchor="start" x="413" y="-84.8" font-family="arial" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="364" y="-67.8" font-family="arial" font-size="14.00">X1:5</text>
|
||||
<text text-anchor="start" x="406" y="-67.8" font-family="arial" font-size="14.00">YE</text>
|
||||
<text text-anchor="start" x="438.5" y="-67.8" font-family="arial" font-size="14.00">X2:7</text>
|
||||
<polygon fill="#ffff00" stroke="transparent" points="357.5,-56 357.5,-62 472.5,-62 472.5,-56 357.5,-56"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="358.5,-57 471.5,-57 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="471.5,-61 358.5,-61 "/>
|
||||
<text text-anchor="start" x="364" y="-42.8" font-family="arial" font-size="14.00">X1:6</text>
|
||||
<text text-anchor="start" x="404.5" y="-42.8" font-family="arial" font-size="14.00">GN</text>
|
||||
<text text-anchor="start" x="438.5" y="-42.8" font-family="arial" font-size="14.00">X2:2</text>
|
||||
<polygon fill="#00ff00" stroke="transparent" stroke-width="2" points="357.5,-31 357.5,-37 472.5,-37 472.5,-31 357.5,-31"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="358.5,-32 471.5,-32 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="471.5,-36 358.5,-36 "/>
|
||||
<text text-anchor="start" x="376" y="-17.8" font-family="arial" font-size="14.00"> </text>
|
||||
</g>
|
||||
<!-- X1--C1 -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>X1:e--C1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M213,-56C277.13,-56 293.12,-57 357,-57"/>
|
||||
<path fill="none" stroke="#ffff00" stroke-width="2" d="M213,-58C277,-58 293,-59 357,-59"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M213,-60C276.88,-60 292.87,-61 357,-61"/>
|
||||
</g>
|
||||
<!-- X1--C1 -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>X1:e--C1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M213,-33C276.88,-33 292.87,-32 357,-32"/>
|
||||
<path fill="none" stroke="#00ff00" stroke-width="2" d="M213,-35C277,-35 293,-34 357,-34"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M213,-37C277.13,-37 293.12,-36 357,-36"/>
|
||||
</g>
|
||||
<!-- X2 -->
|
||||
<g id="node2" class="node">
|
||||
<title>X2</title>
|
||||
<polygon fill="white" stroke="black" points="616,-0.5 616,-115.5 829,-115.5 829,-0.5 616,-0.5"/>
|
||||
<text text-anchor="middle" x="722.5" y="-100.3" font-family="arial" font-size="14.00">X2</text>
|
||||
<polyline fill="none" stroke="black" points="616,-92.5 829,-92.5 "/>
|
||||
<text text-anchor="middle" x="652" y="-77.3" font-family="arial" font-size="14.00">D-Sub</text>
|
||||
<polyline fill="none" stroke="black" points="688,-69.5 688,-92.5 "/>
|
||||
<text text-anchor="middle" x="726" y="-77.3" font-family="arial" font-size="14.00">female</text>
|
||||
<polyline fill="none" stroke="black" points="764,-69.5 764,-92.5 "/>
|
||||
<text text-anchor="middle" x="796.5" y="-77.3" font-family="arial" font-size="14.00">9-pin</text>
|
||||
<polyline fill="none" stroke="black" points="616,-69.5 829,-69.5 "/>
|
||||
<text text-anchor="middle" x="722.5" y="-54.3" font-family="arial" font-size="14.00">2</text>
|
||||
<polyline fill="none" stroke="black" points="616,-46.5 829,-46.5 "/>
|
||||
<text text-anchor="middle" x="722.5" y="-31.3" font-family="arial" font-size="14.00">7</text>
|
||||
<polyline fill="none" stroke="black" points="616,-23.5 829,-23.5 "/>
|
||||
<text text-anchor="middle" x="722.5" y="-8.3" font-family="arial" font-size="14.00">Unconnected pins are not shown</text>
|
||||
</g>
|
||||
<!-- C1--X2 -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>C1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M472,-57C535.16,-57.98 549.4,-33.98 616,-33"/>
|
||||
<path fill="none" stroke="#ffff00" stroke-width="2" d="M472,-59C536.88,-59 551.12,-35 616,-35"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M472,-61C538.6,-60.02 552.84,-36.02 616,-37"/>
|
||||
</g>
|
||||
<!-- C1--X2 -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>C1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M472,-32C538.6,-32.98 552.84,-56.98 616,-56"/>
|
||||
<path fill="none" stroke="#00ff00" stroke-width="2" d="M472,-34C536.88,-34 551.12,-58 616,-58"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M472,-36C535.16,-35.02 549.4,-59.02 616,-60"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<h1>Bill of Materials</h1><table style="border:1px solid #000000; font-size: 14pt; border-spacing: 0px"><tr><th align="left" style="border:1px solid #000000; padding: 8px">Item</th><th align="left" style="border:1px solid #000000; padding: 8px">Qty</th><th align="left" style="border:1px solid #000000; padding: 8px">Unit</th><th align="left" style="border:1px solid #000000; padding: 8px">Designators</th></tr><tr><td style="border:1px solid #000000; padding: 4px">Connector, D-Sub, female, 9 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">1</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X2</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Connector, TE 776164-1, female, 35 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">1</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X1</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Cable, 2 x 20 AWG</td><td align="right" style="border:1px solid #000000; padding: 4px">1</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">C1</td></tr></table></body></html>
|
||||
BIN
examples/ex07.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
103
examples/ex07.svg
Normal file
@ -0,0 +1,103 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.44.0 (20200408.0750)
|
||||
-->
|
||||
<!-- Pages: 1 -->
|
||||
<svg width="837pt" height="150pt"
|
||||
viewBox="0.00 0.00 837.00 150.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 146)">
|
||||
<polygon fill="white" stroke="transparent" points="-4,4 -4,-146 833,-146 833,4 -4,4"/>
|
||||
<!-- X1 -->
|
||||
<g id="node1" class="node">
|
||||
<title>X1</title>
|
||||
<polygon fill="white" stroke="black" points="0,-0.5 0,-115.5 213,-115.5 213,-0.5 0,-0.5"/>
|
||||
<text text-anchor="middle" x="106.5" y="-100.3" font-family="arial" font-size="14.00">X1</text>
|
||||
<polyline fill="none" stroke="black" points="0,-92.5 213,-92.5 "/>
|
||||
<text text-anchor="middle" x="48.5" y="-77.3" font-family="arial" font-size="14.00">TE 776164-1</text>
|
||||
<polyline fill="none" stroke="black" points="97,-69.5 97,-92.5 "/>
|
||||
<text text-anchor="middle" x="127" y="-77.3" font-family="arial" font-size="14.00">female</text>
|
||||
<polyline fill="none" stroke="black" points="157,-69.5 157,-92.5 "/>
|
||||
<text text-anchor="middle" x="185" y="-77.3" font-family="arial" font-size="14.00">35-pin</text>
|
||||
<polyline fill="none" stroke="black" points="0,-69.5 213,-69.5 "/>
|
||||
<text text-anchor="middle" x="106.5" y="-54.3" font-family="arial" font-size="14.00">5</text>
|
||||
<polyline fill="none" stroke="black" points="0,-46.5 213,-46.5 "/>
|
||||
<text text-anchor="middle" x="106.5" y="-31.3" font-family="arial" font-size="14.00">6</text>
|
||||
<polyline fill="none" stroke="black" points="0,-23.5 213,-23.5 "/>
|
||||
<text text-anchor="middle" x="106.5" y="-8.3" font-family="arial" font-size="14.00">Unconnected pins are not shown</text>
|
||||
</g>
|
||||
<!-- C1 -->
|
||||
<g id="node3" class="node">
|
||||
<title>C1</title>
|
||||
<polygon fill="none" stroke="black" points="472,-142 357,-142 357,-12 472,-12 472,-142"/>
|
||||
<polygon fill="none" stroke="black" points="357.5,-119 357.5,-142 472.5,-142 472.5,-119 357.5,-119"/>
|
||||
<text text-anchor="start" x="406" y="-126.8" font-family="arial" font-size="14.00">C1</text>
|
||||
<polygon fill="none" stroke="black" points="357.5,-96 357.5,-119 380.5,-119 380.5,-96 357.5,-96"/>
|
||||
<text text-anchor="start" x="361.5" y="-103.8" font-family="arial" font-size="14.00">2x</text>
|
||||
<polygon fill="none" stroke="black" points="380.5,-96 380.5,-119 440.5,-119 440.5,-96 380.5,-96"/>
|
||||
<text text-anchor="start" x="384.5" y="-103.8" font-family="arial" font-size="14.00">20 AWG</text>
|
||||
<polygon fill="none" stroke="black" points="440.5,-96 440.5,-119 472.5,-119 472.5,-96 440.5,-96"/>
|
||||
<text text-anchor="start" x="444.5" y="-103.8" font-family="arial" font-size="14.00">1 m</text>
|
||||
<text text-anchor="start" x="413" y="-84.8" font-family="arial" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="364" y="-67.8" font-family="arial" font-size="14.00">X1:5</text>
|
||||
<text text-anchor="start" x="406" y="-67.8" font-family="arial" font-size="14.00">YE</text>
|
||||
<text text-anchor="start" x="438.5" y="-67.8" font-family="arial" font-size="14.00">X2:7</text>
|
||||
<polygon fill="#ffff00" stroke="transparent" points="357.5,-56 357.5,-62 472.5,-62 472.5,-56 357.5,-56"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="358.5,-57 471.5,-57 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="471.5,-61 358.5,-61 "/>
|
||||
<text text-anchor="start" x="364" y="-42.8" font-family="arial" font-size="14.00">X1:6</text>
|
||||
<text text-anchor="start" x="404.5" y="-42.8" font-family="arial" font-size="14.00">GN</text>
|
||||
<text text-anchor="start" x="438.5" y="-42.8" font-family="arial" font-size="14.00">X2:2</text>
|
||||
<polygon fill="#00ff00" stroke="transparent" stroke-width="2" points="357.5,-31 357.5,-37 472.5,-37 472.5,-31 357.5,-31"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="358.5,-32 471.5,-32 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="471.5,-36 358.5,-36 "/>
|
||||
<text text-anchor="start" x="376" y="-17.8" font-family="arial" font-size="14.00"> </text>
|
||||
</g>
|
||||
<!-- X1--C1 -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>X1:e--C1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M213,-56C277.13,-56 293.12,-57 357,-57"/>
|
||||
<path fill="none" stroke="#ffff00" stroke-width="2" d="M213,-58C277,-58 293,-59 357,-59"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M213,-60C276.88,-60 292.87,-61 357,-61"/>
|
||||
</g>
|
||||
<!-- X1--C1 -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>X1:e--C1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M213,-33C276.88,-33 292.87,-32 357,-32"/>
|
||||
<path fill="none" stroke="#00ff00" stroke-width="2" d="M213,-35C277,-35 293,-34 357,-34"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M213,-37C277.13,-37 293.12,-36 357,-36"/>
|
||||
</g>
|
||||
<!-- X2 -->
|
||||
<g id="node2" class="node">
|
||||
<title>X2</title>
|
||||
<polygon fill="white" stroke="black" points="616,-0.5 616,-115.5 829,-115.5 829,-0.5 616,-0.5"/>
|
||||
<text text-anchor="middle" x="722.5" y="-100.3" font-family="arial" font-size="14.00">X2</text>
|
||||
<polyline fill="none" stroke="black" points="616,-92.5 829,-92.5 "/>
|
||||
<text text-anchor="middle" x="652" y="-77.3" font-family="arial" font-size="14.00">D-Sub</text>
|
||||
<polyline fill="none" stroke="black" points="688,-69.5 688,-92.5 "/>
|
||||
<text text-anchor="middle" x="726" y="-77.3" font-family="arial" font-size="14.00">female</text>
|
||||
<polyline fill="none" stroke="black" points="764,-69.5 764,-92.5 "/>
|
||||
<text text-anchor="middle" x="796.5" y="-77.3" font-family="arial" font-size="14.00">9-pin</text>
|
||||
<polyline fill="none" stroke="black" points="616,-69.5 829,-69.5 "/>
|
||||
<text text-anchor="middle" x="722.5" y="-54.3" font-family="arial" font-size="14.00">2</text>
|
||||
<polyline fill="none" stroke="black" points="616,-46.5 829,-46.5 "/>
|
||||
<text text-anchor="middle" x="722.5" y="-31.3" font-family="arial" font-size="14.00">7</text>
|
||||
<polyline fill="none" stroke="black" points="616,-23.5 829,-23.5 "/>
|
||||
<text text-anchor="middle" x="722.5" y="-8.3" font-family="arial" font-size="14.00">Unconnected pins are not shown</text>
|
||||
</g>
|
||||
<!-- C1--X2 -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>C1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M472,-57C535.16,-57.98 549.4,-33.98 616,-33"/>
|
||||
<path fill="none" stroke="#ffff00" stroke-width="2" d="M472,-59C536.88,-59 551.12,-35 616,-35"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M472,-61C538.6,-60.02 552.84,-36.02 616,-37"/>
|
||||
</g>
|
||||
<!-- C1--X2 -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>C1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M472,-32C538.6,-32.98 552.84,-56.98 616,-56"/>
|
||||
<path fill="none" stroke="#00ff00" stroke-width="2" d="M472,-34C536.88,-34 551.12,-58 616,-58"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M472,-36C535.16,-35.02 549.4,-59.02 616,-60"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.7 KiB |
29
examples/ex07.yml
Normal file
@ -0,0 +1,29 @@
|
||||
# contributed by @elliotmr
|
||||
|
||||
connectors:
|
||||
X1:
|
||||
type: TE 776164-1
|
||||
subtype: female
|
||||
hide_disconnected_pins: True
|
||||
pincount: 35
|
||||
notes: Unconnected pins are not shown
|
||||
|
||||
X2:
|
||||
type: D-Sub
|
||||
subtype: female
|
||||
pincount: 9
|
||||
hide_disconnected_pins: True
|
||||
notes: Unconnected pins are not shown
|
||||
|
||||
cables:
|
||||
C1:
|
||||
wirecount: 2
|
||||
gauge: 20 AWG
|
||||
colors: [YE, GN]
|
||||
length: 1
|
||||
|
||||
connections:
|
||||
-
|
||||
- X1: [5,6]
|
||||
- C1: [1,2]
|
||||
- X2: [7,2]
|
||||
3
examples/ex08.bom.tsv
Normal file
@ -0,0 +1,3 @@
|
||||
Item Qty Unit Designators
|
||||
Connector, Phone Connector, male 3.5, 3 pins 1 Key
|
||||
Cable, 3 x 24 AWG shielded 0.2 m W1
|
||||
|
17
examples/ex08.gv
Normal file
@ -0,0 +1,17 @@
|
||||
graph {
|
||||
// Graph generated by WireViz
|
||||
// https://github.com/formatc1702/WireViz
|
||||
graph [bgcolor=white fontname=arial nodesep=0.33 rankdir=LR ranksep=2]
|
||||
node [fillcolor=white fontname=arial shape=record style=filled]
|
||||
edge [fontname=arial style=bold]
|
||||
Key [label="Key|{Phone Connector|male 3.5}|{{Dot|Dash|Ground}|{<pTr>T|<pRr>R|<pSr>S}}"]
|
||||
edge [color="#000000:#ffffff:#000000"]
|
||||
Key:pSr:e -- W1:w1:w
|
||||
edge [color="#000000:#666600:#000000"]
|
||||
Key:pRr:e -- W1:w2:w
|
||||
edge [color="#000000:#00ff00:#000000"]
|
||||
Key:pTr:e -- W1:w3:w
|
||||
edge [color="#000000"]
|
||||
Key:pSr:e -- W1:ws:w
|
||||
W1 [label=<<table border="0" cellspacing="0" cellpadding="0"><tr><td><table border="0" cellspacing="0" cellpadding="3" cellborder="1"><tr><td colspan="4">W1</td></tr><tr><td>3x</td><td>24 AWG</td><td>+ S</td><td>0.2 m</td></tr></table></td></tr><tr><td> </td></tr><tr><td><table border="0" cellspacing="0" cellborder="0"><tr><td>Key:S</td><td>WH</td><td><!-- 1_out --></td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#ffffff" border="2" sides="tb" port="w1"></td></tr><tr><td>Key:R</td><td>BN</td><td><!-- 2_out --></td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#666600" border="2" sides="tb" port="w2"></td></tr><tr><td>Key:T</td><td>GN</td><td><!-- 3_out --></td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#00ff00" border="2" sides="tb" port="w3"></td></tr><tr><td> </td></tr><tr><td>Key:S</td><td>Shield</td><td><!-- s_out --></td></tr><tr><td colspan="3" cellpadding="0" height="6" border="2" sides="b" port="ws"></td></tr><tr><td> </td></tr></table></td></tr></table>> fillcolor=white margin=0 shape=box style=""]
|
||||
}
|
||||
97
examples/ex08.html
Normal file
@ -0,0 +1,97 @@
|
||||
<html><body style="font-family:Arial"><h1>Diagram</h1><?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.44.0 (20200408.0750)
|
||||
-->
|
||||
<!-- Pages: 1 -->
|
||||
<svg width="499pt" height="207pt"
|
||||
viewBox="0.00 0.00 499.00 207.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 203)">
|
||||
<polygon fill="white" stroke="transparent" points="-4,4 -4,-203 495,-203 495,4 -4,4"/>
|
||||
<!-- Key -->
|
||||
<g id="node1" class="node">
|
||||
<title>Key</title>
|
||||
<polygon fill="white" stroke="black" points="0,-33 0,-148 191,-148 191,-33 0,-33"/>
|
||||
<text text-anchor="middle" x="95.5" y="-132.8" font-family="arial" font-size="14.00">Key</text>
|
||||
<polyline fill="none" stroke="black" points="0,-125 191,-125 "/>
|
||||
<text text-anchor="middle" x="61" y="-109.8" font-family="arial" font-size="14.00">Phone Connector</text>
|
||||
<polyline fill="none" stroke="black" points="122,-102 122,-125 "/>
|
||||
<text text-anchor="middle" x="156.5" y="-109.8" font-family="arial" font-size="14.00">male 3.5</text>
|
||||
<polyline fill="none" stroke="black" points="0,-102 191,-102 "/>
|
||||
<text text-anchor="middle" x="56.5" y="-86.8" font-family="arial" font-size="14.00">Dot</text>
|
||||
<polyline fill="none" stroke="black" points="0,-79 113,-79 "/>
|
||||
<text text-anchor="middle" x="56.5" y="-63.8" font-family="arial" font-size="14.00">Dash</text>
|
||||
<polyline fill="none" stroke="black" points="0,-56 113,-56 "/>
|
||||
<text text-anchor="middle" x="56.5" y="-40.8" font-family="arial" font-size="14.00">Ground</text>
|
||||
<polyline fill="none" stroke="black" points="113,-33 113,-102 "/>
|
||||
<text text-anchor="middle" x="152" y="-86.8" font-family="arial" font-size="14.00">T</text>
|
||||
<polyline fill="none" stroke="black" points="113,-79 191,-79 "/>
|
||||
<text text-anchor="middle" x="152" y="-63.8" font-family="arial" font-size="14.00">R</text>
|
||||
<polyline fill="none" stroke="black" points="113,-56 191,-56 "/>
|
||||
<text text-anchor="middle" x="152" y="-40.8" font-family="arial" font-size="14.00">S</text>
|
||||
</g>
|
||||
<!-- W1 -->
|
||||
<g id="node2" class="node">
|
||||
<title>W1</title>
|
||||
<polygon fill="none" stroke="black" points="491,-199 335,-199 335,0 491,0 491,-199"/>
|
||||
<polygon fill="none" stroke="black" points="335,-175.5 335,-198.5 491,-198.5 491,-175.5 335,-175.5"/>
|
||||
<text text-anchor="start" x="402" y="-183.3" font-family="arial" font-size="14.00">W1</text>
|
||||
<polygon fill="none" stroke="black" points="335,-152.5 335,-175.5 358,-175.5 358,-152.5 335,-152.5"/>
|
||||
<text text-anchor="start" x="339" y="-160.3" font-family="arial" font-size="14.00">3x</text>
|
||||
<polygon fill="none" stroke="black" points="358,-152.5 358,-175.5 418,-175.5 418,-152.5 358,-152.5"/>
|
||||
<text text-anchor="start" x="362" y="-160.3" font-family="arial" font-size="14.00">24 AWG</text>
|
||||
<polygon fill="none" stroke="black" points="418,-152.5 418,-175.5 448,-175.5 448,-152.5 418,-152.5"/>
|
||||
<text text-anchor="start" x="422" y="-160.3" font-family="arial" font-size="14.00">+ S</text>
|
||||
<polygon fill="none" stroke="black" points="448,-152.5 448,-175.5 491,-175.5 491,-152.5 448,-152.5"/>
|
||||
<text text-anchor="start" x="452" y="-160.3" font-family="arial" font-size="14.00">0.2 m</text>
|
||||
<text text-anchor="start" x="411" y="-141.3" font-family="arial" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="348.5" y="-124.3" font-family="arial" font-size="14.00">Key:S</text>
|
||||
<text text-anchor="start" x="419.5" y="-124.3" font-family="arial" font-size="14.00">WH</text>
|
||||
<polygon fill="#ffffff" stroke="transparent" points="335,-112.5 335,-118.5 491,-118.5 491,-112.5 335,-112.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="336,-113.5 490,-113.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="490,-117.5 336,-117.5 "/>
|
||||
<text text-anchor="start" x="348.5" y="-99.3" font-family="arial" font-size="14.00">Key:R</text>
|
||||
<text text-anchor="start" x="422" y="-99.3" font-family="arial" font-size="14.00">BN</text>
|
||||
<polygon fill="#666600" stroke="transparent" stroke-width="2" points="335,-87.5 335,-93.5 491,-93.5 491,-87.5 335,-87.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="336,-88.5 490,-88.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="490,-92.5 336,-92.5 "/>
|
||||
<text text-anchor="start" x="349" y="-74.3" font-family="arial" font-size="14.00">Key:T</text>
|
||||
<text text-anchor="start" x="420.5" y="-74.3" font-family="arial" font-size="14.00">GN</text>
|
||||
<polygon fill="#00ff00" stroke="transparent" stroke-width="2" points="335,-62.5 335,-68.5 491,-68.5 491,-62.5 335,-62.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="336,-63.5 490,-63.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="490,-67.5 336,-67.5 "/>
|
||||
<text text-anchor="start" x="365" y="-49.3" font-family="arial" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="348.5" y="-30.3" font-family="arial" font-size="14.00">Key:S</text>
|
||||
<text text-anchor="start" x="412.5" y="-30.3" font-family="arial" font-size="14.00">Shield</text>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="336,-19.5 490,-19.5 "/>
|
||||
<text text-anchor="start" x="365" y="-5.3" font-family="arial" font-size="14.00"> </text>
|
||||
</g>
|
||||
<!-- Key--W1 -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>Key:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M191,-42.5C264.36,-44.46 265.64,-115.46 335,-113.5"/>
|
||||
<path fill="none" stroke="#ffffff" stroke-width="2" d="M191,-44.5C262.36,-44.5 263.64,-115.5 335,-115.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M191,-46.5C260.36,-44.54 261.64,-115.54 335,-117.5"/>
|
||||
</g>
|
||||
<!-- Key--W1 -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>Key:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M191,-65.5C257.51,-66.44 271.88,-89.44 335,-88.5"/>
|
||||
<path fill="none" stroke="#666600" stroke-width="2" d="M191,-67.5C255.81,-67.5 270.19,-90.5 335,-90.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M191,-69.5C254.12,-68.56 268.49,-91.56 335,-92.5"/>
|
||||
</g>
|
||||
<!-- Key--W1 -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>Key:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M191,-88.5C254.21,-89.52 268.3,-64.52 335,-63.5"/>
|
||||
<path fill="none" stroke="#00ff00" stroke-width="2" d="M191,-90.5C255.96,-90.5 270.04,-65.5 335,-65.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M191,-92.5C257.7,-91.48 271.79,-66.48 335,-67.5"/>
|
||||
</g>
|
||||
<!-- Key--W1 -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>Key:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M191,-44.5C255.81,-44.5 270.19,-21.5 335,-21.5"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<h1>Bill of Materials</h1><table style="border:1px solid #000000; font-size: 14pt; border-spacing: 0px"><tr><th align="left" style="border:1px solid #000000; padding: 8px">Item</th><th align="left" style="border:1px solid #000000; padding: 8px">Qty</th><th align="left" style="border:1px solid #000000; padding: 8px">Unit</th><th align="left" style="border:1px solid #000000; padding: 8px">Designators</th></tr><tr><td style="border:1px solid #000000; padding: 4px">Connector, Phone Connector, male 3.5, 3 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">1</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">Key</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Cable, 3 x 24 AWG shielded</td><td align="right" style="border:1px solid #000000; padding: 4px">0.2</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1</td></tr></table></body></html>
|
||||
BIN
examples/ex08.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
96
examples/ex08.svg
Normal file
@ -0,0 +1,96 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.44.0 (20200408.0750)
|
||||
-->
|
||||
<!-- Pages: 1 -->
|
||||
<svg width="499pt" height="207pt"
|
||||
viewBox="0.00 0.00 499.00 207.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 203)">
|
||||
<polygon fill="white" stroke="transparent" points="-4,4 -4,-203 495,-203 495,4 -4,4"/>
|
||||
<!-- Key -->
|
||||
<g id="node1" class="node">
|
||||
<title>Key</title>
|
||||
<polygon fill="white" stroke="black" points="0,-33 0,-148 191,-148 191,-33 0,-33"/>
|
||||
<text text-anchor="middle" x="95.5" y="-132.8" font-family="arial" font-size="14.00">Key</text>
|
||||
<polyline fill="none" stroke="black" points="0,-125 191,-125 "/>
|
||||
<text text-anchor="middle" x="61" y="-109.8" font-family="arial" font-size="14.00">Phone Connector</text>
|
||||
<polyline fill="none" stroke="black" points="122,-102 122,-125 "/>
|
||||
<text text-anchor="middle" x="156.5" y="-109.8" font-family="arial" font-size="14.00">male 3.5</text>
|
||||
<polyline fill="none" stroke="black" points="0,-102 191,-102 "/>
|
||||
<text text-anchor="middle" x="56.5" y="-86.8" font-family="arial" font-size="14.00">Dot</text>
|
||||
<polyline fill="none" stroke="black" points="0,-79 113,-79 "/>
|
||||
<text text-anchor="middle" x="56.5" y="-63.8" font-family="arial" font-size="14.00">Dash</text>
|
||||
<polyline fill="none" stroke="black" points="0,-56 113,-56 "/>
|
||||
<text text-anchor="middle" x="56.5" y="-40.8" font-family="arial" font-size="14.00">Ground</text>
|
||||
<polyline fill="none" stroke="black" points="113,-33 113,-102 "/>
|
||||
<text text-anchor="middle" x="152" y="-86.8" font-family="arial" font-size="14.00">T</text>
|
||||
<polyline fill="none" stroke="black" points="113,-79 191,-79 "/>
|
||||
<text text-anchor="middle" x="152" y="-63.8" font-family="arial" font-size="14.00">R</text>
|
||||
<polyline fill="none" stroke="black" points="113,-56 191,-56 "/>
|
||||
<text text-anchor="middle" x="152" y="-40.8" font-family="arial" font-size="14.00">S</text>
|
||||
</g>
|
||||
<!-- W1 -->
|
||||
<g id="node2" class="node">
|
||||
<title>W1</title>
|
||||
<polygon fill="none" stroke="black" points="491,-199 335,-199 335,0 491,0 491,-199"/>
|
||||
<polygon fill="none" stroke="black" points="335,-175.5 335,-198.5 491,-198.5 491,-175.5 335,-175.5"/>
|
||||
<text text-anchor="start" x="402" y="-183.3" font-family="arial" font-size="14.00">W1</text>
|
||||
<polygon fill="none" stroke="black" points="335,-152.5 335,-175.5 358,-175.5 358,-152.5 335,-152.5"/>
|
||||
<text text-anchor="start" x="339" y="-160.3" font-family="arial" font-size="14.00">3x</text>
|
||||
<polygon fill="none" stroke="black" points="358,-152.5 358,-175.5 418,-175.5 418,-152.5 358,-152.5"/>
|
||||
<text text-anchor="start" x="362" y="-160.3" font-family="arial" font-size="14.00">24 AWG</text>
|
||||
<polygon fill="none" stroke="black" points="418,-152.5 418,-175.5 448,-175.5 448,-152.5 418,-152.5"/>
|
||||
<text text-anchor="start" x="422" y="-160.3" font-family="arial" font-size="14.00">+ S</text>
|
||||
<polygon fill="none" stroke="black" points="448,-152.5 448,-175.5 491,-175.5 491,-152.5 448,-152.5"/>
|
||||
<text text-anchor="start" x="452" y="-160.3" font-family="arial" font-size="14.00">0.2 m</text>
|
||||
<text text-anchor="start" x="411" y="-141.3" font-family="arial" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="348.5" y="-124.3" font-family="arial" font-size="14.00">Key:S</text>
|
||||
<text text-anchor="start" x="419.5" y="-124.3" font-family="arial" font-size="14.00">WH</text>
|
||||
<polygon fill="#ffffff" stroke="transparent" points="335,-112.5 335,-118.5 491,-118.5 491,-112.5 335,-112.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="336,-113.5 490,-113.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="490,-117.5 336,-117.5 "/>
|
||||
<text text-anchor="start" x="348.5" y="-99.3" font-family="arial" font-size="14.00">Key:R</text>
|
||||
<text text-anchor="start" x="422" y="-99.3" font-family="arial" font-size="14.00">BN</text>
|
||||
<polygon fill="#666600" stroke="transparent" stroke-width="2" points="335,-87.5 335,-93.5 491,-93.5 491,-87.5 335,-87.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="336,-88.5 490,-88.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="490,-92.5 336,-92.5 "/>
|
||||
<text text-anchor="start" x="349" y="-74.3" font-family="arial" font-size="14.00">Key:T</text>
|
||||
<text text-anchor="start" x="420.5" y="-74.3" font-family="arial" font-size="14.00">GN</text>
|
||||
<polygon fill="#00ff00" stroke="transparent" stroke-width="2" points="335,-62.5 335,-68.5 491,-68.5 491,-62.5 335,-62.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="336,-63.5 490,-63.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="490,-67.5 336,-67.5 "/>
|
||||
<text text-anchor="start" x="365" y="-49.3" font-family="arial" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="348.5" y="-30.3" font-family="arial" font-size="14.00">Key:S</text>
|
||||
<text text-anchor="start" x="412.5" y="-30.3" font-family="arial" font-size="14.00">Shield</text>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="336,-19.5 490,-19.5 "/>
|
||||
<text text-anchor="start" x="365" y="-5.3" font-family="arial" font-size="14.00"> </text>
|
||||
</g>
|
||||
<!-- Key--W1 -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>Key:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M191,-42.5C264.36,-44.46 265.64,-115.46 335,-113.5"/>
|
||||
<path fill="none" stroke="#ffffff" stroke-width="2" d="M191,-44.5C262.36,-44.5 263.64,-115.5 335,-115.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M191,-46.5C260.36,-44.54 261.64,-115.54 335,-117.5"/>
|
||||
</g>
|
||||
<!-- Key--W1 -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>Key:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M191,-65.5C257.51,-66.44 271.88,-89.44 335,-88.5"/>
|
||||
<path fill="none" stroke="#666600" stroke-width="2" d="M191,-67.5C255.81,-67.5 270.19,-90.5 335,-90.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M191,-69.5C254.12,-68.56 268.49,-91.56 335,-92.5"/>
|
||||
</g>
|
||||
<!-- Key--W1 -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>Key:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M191,-88.5C254.21,-89.52 268.3,-64.52 335,-63.5"/>
|
||||
<path fill="none" stroke="#00ff00" stroke-width="2" d="M191,-90.5C255.96,-90.5 270.04,-65.5 335,-65.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M191,-92.5C257.7,-91.48 271.79,-66.48 335,-67.5"/>
|
||||
</g>
|
||||
<!-- Key--W1 -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>Key:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M191,-44.5C255.81,-44.5 270.19,-21.5 335,-21.5"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.5 KiB |
25
examples/ex08.yml
Normal file
@ -0,0 +1,25 @@
|
||||
# contributed by @cocide
|
||||
|
||||
connectors:
|
||||
Key:
|
||||
type: Phone Connector
|
||||
subtype: male 3.5
|
||||
pinnumbers: [T, R, S]
|
||||
pinout: [Dot, Dash, Ground]
|
||||
show_pincount: false
|
||||
|
||||
cables:
|
||||
W1:
|
||||
gauge: 24 AWG
|
||||
length: 0.2
|
||||
color_code: DIN
|
||||
wirecount: 3
|
||||
shield: true
|
||||
|
||||
connections:
|
||||
-
|
||||
- Key: [S,R,T]
|
||||
- W1: [1,2,3]
|
||||
-
|
||||
- Key: S
|
||||
- W1: s
|
||||
4
examples/ex09.bom.tsv
Normal file
@ -0,0 +1,4 @@
|
||||
Item Qty Unit Designators
|
||||
Connector, D-Sub, male, 25 pins 1 X1
|
||||
Connector, F48, female, 48 pins 1 X2
|
||||
Cable, 12 x 0.25 mm² shielded 0.2 m W1
|
||||
|
48
examples/ex09.gv
Normal file
@ -0,0 +1,48 @@
|
||||
graph {
|
||||
// Graph generated by WireViz
|
||||
// https://github.com/formatc1702/WireViz
|
||||
graph [bgcolor=white fontname=arial nodesep=0.33 rankdir=LR ranksep=2]
|
||||
node [fillcolor=white fontname=arial shape=record style=filled]
|
||||
edge [fontname=arial style=bold]
|
||||
X1 [label="X1|{D-Sub|male|25-pin}|{{SENSE_P_1|SENSE_N_1|SENSE_P_2|SENSE_N_2|SENSE_P_3|SENSE_N_3|SENSE_P_4|SENSE_N_4|SENSE_P_5|SENSE_N_5|SENSE_P_6|SENSE_N_6|GND}|{<p1r>1|<p14r>14|<p3r>3|<p16r>16|<p5r>5|<p18r>18|<p7r>7|<p20r>20|<p9r>9|<p22r>22|<p11r>11|<p24r>24|<p13r>13}}"]
|
||||
X2 [label="X2|{F48|female|48-pin}|{{<pz2l>z2|<pb2l>b2|<pd2l>d2|<pz4l>z4|<pb4l>b4|<pd4l>d4|<pz6l>z6|<pb6l>b6|<pd6l>d6|<pz8l>z8|<pb8l>b8|<pd8l>d8|<pz10l>z10|<pb10l>b10|<pd10l>d10|<pz12l>z12|<pb12l>b12|<pd12l>d12|<pz14l>z14|<pb14l>b14|<pd14l>d14|<pz16l>z16|<pb16l>b16|<pd16l>d16|<pz18l>z18|<pb18l>b18|<pd18l>d18|<pz20l>z20|<pb20l>b20|<pd20l>d20|<pz22l>z22|<pb22l>b22|<pd22l>d22|<pz24l>z24|<pb24l>b24|<pd24l>d24|<pz26l>z26|<pb26l>b26|<pd26l>d26|<pz28l>z28|<pb28l>b28|<pd28l>d28|<pz30l>z30|<pb30l>b30|<pd30l>d30|<pz32l>z32|<pb32l>b32|<pd32l>d32}}"]
|
||||
edge [color="#000000:#666600:#000000"]
|
||||
X1:p1r:e -- W1:w2:w
|
||||
W1:w2:e -- X2:pd4l:w
|
||||
edge [color="#000000:#ffffff:#000000"]
|
||||
X1:p14r:e -- W1:w1:w
|
||||
W1:w1:e -- X2:pz2l:w
|
||||
edge [color="#000000:#ffff00:#000000"]
|
||||
X1:p3r:e -- W1:w4:w
|
||||
W1:w4:e -- X2:pd10l:w
|
||||
edge [color="#000000:#00ff00:#000000"]
|
||||
X1:p16r:e -- W1:w3:w
|
||||
W1:w3:e -- X2:pz8l:w
|
||||
edge [color="#000000:#ff66cc:#000000"]
|
||||
X1:p5r:e -- W1:w6:w
|
||||
W1:w6:e -- X2:pd16l:w
|
||||
edge [color="#000000:#999999:#000000"]
|
||||
X1:p18r:e -- W1:w5:w
|
||||
W1:w5:e -- X2:pz14l:w
|
||||
edge [color="#000000:#ff0000:#000000"]
|
||||
X1:p7r:e -- W1:w8:w
|
||||
W1:w8:e -- X2:pd20l:w
|
||||
edge [color="#000000:#0066ff:#000000"]
|
||||
X1:p20r:e -- W1:w7:w
|
||||
W1:w7:e -- X2:pz18l:w
|
||||
edge [color="#000000:#8000ff:#000000"]
|
||||
X1:p9r:e -- W1:w10:w
|
||||
W1:w10:e -- X2:pd26l:w
|
||||
edge [color="#000000:#000000:#000000"]
|
||||
X1:p22r:e -- W1:w9:w
|
||||
W1:w9:e -- X2:pz24l:w
|
||||
edge [color="#000000:#666600:#000000"]
|
||||
X1:p11r:e -- W1:w12:w
|
||||
W1:w12:e -- X2:pd32l:w
|
||||
edge [color="#000000:#ffffff:#000000"]
|
||||
X1:p24r:e -- W1:w11:w
|
||||
W1:w11:e -- X2:pz30l:w
|
||||
edge [color="#000000"]
|
||||
X1:p13r:e -- W1:ws:w
|
||||
W1 [label=<<table border="0" cellspacing="0" cellpadding="0"><tr><td><table border="0" cellspacing="0" cellpadding="3" cellborder="1"><tr><td colspan="4">W1</td></tr><tr><td>12x</td><td>0.25 mm²</td><td>+ S</td><td>0.2 m</td></tr></table></td></tr><tr><td> </td></tr><tr><td><table border="0" cellspacing="0" cellborder="0"><tr><td>X1:14</td><td>WH</td><td>X2:z2</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#ffffff" border="2" sides="tb" port="w1"></td></tr><tr><td>X1:1</td><td>BN</td><td>X2:d4</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#666600" border="2" sides="tb" port="w2"></td></tr><tr><td>X1:16</td><td>GN</td><td>X2:z8</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#00ff00" border="2" sides="tb" port="w3"></td></tr><tr><td>X1:3</td><td>YE</td><td>X2:d10</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#ffff00" border="2" sides="tb" port="w4"></td></tr><tr><td>X1:18</td><td>GY</td><td>X2:z14</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#999999" border="2" sides="tb" port="w5"></td></tr><tr><td>X1:5</td><td>PK</td><td>X2:d16</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#ff66cc" border="2" sides="tb" port="w6"></td></tr><tr><td>X1:20</td><td>BU</td><td>X2:z18</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#0066ff" border="2" sides="tb" port="w7"></td></tr><tr><td>X1:7</td><td>RD</td><td>X2:d20</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#ff0000" border="2" sides="tb" port="w8"></td></tr><tr><td>X1:22</td><td>BK</td><td>X2:z24</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#000000" border="2" sides="tb" port="w9"></td></tr><tr><td>X1:9</td><td>VT</td><td>X2:d26</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#8000ff" border="2" sides="tb" port="w10"></td></tr><tr><td>X1:24</td><td>WH</td><td>X2:z30</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#ffffff" border="2" sides="tb" port="w11"></td></tr><tr><td>X1:11</td><td>BN</td><td>X2:d32</td></tr><tr><td colspan="3" cellpadding="0" height="6" bgcolor="#666600" border="2" sides="tb" port="w12"></td></tr><tr><td> </td></tr><tr><td>X1:13</td><td>Shield</td><td><!-- s_out --></td></tr><tr><td colspan="3" cellpadding="0" height="6" border="2" sides="b" port="ws"></td></tr><tr><td> </td></tr></table></td></tr></table>> fillcolor=white margin=0 shape=box style=""]
|
||||
}
|
||||
451
examples/ex09.html
Normal file
@ -0,0 +1,451 @@
|
||||
<html><body style="font-family:Arial"><h1>Diagram</h1><?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.44.0 (20200408.0750)
|
||||
-->
|
||||
<!-- Pages: 1 -->
|
||||
<svg width="774pt" height="1159pt"
|
||||
viewBox="0.00 0.00 774.00 1159.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 1155)">
|
||||
<polygon fill="white" stroke="transparent" points="-4,4 -4,-1155 770,-1155 770,4 -4,4"/>
|
||||
<!-- X1 -->
|
||||
<g id="node1" class="node">
|
||||
<title>X1</title>
|
||||
<polygon fill="white" stroke="black" points="0,-377 0,-722 156,-722 156,-377 0,-377"/>
|
||||
<text text-anchor="middle" x="78" y="-706.8" font-family="arial" font-size="14.00">X1</text>
|
||||
<polyline fill="none" stroke="black" points="0,-699 156,-699 "/>
|
||||
<text text-anchor="middle" x="27.5" y="-683.8" font-family="arial" font-size="14.00">D-Sub</text>
|
||||
<polyline fill="none" stroke="black" points="55,-676 55,-699 "/>
|
||||
<text text-anchor="middle" x="78.5" y="-683.8" font-family="arial" font-size="14.00">male</text>
|
||||
<polyline fill="none" stroke="black" points="102,-676 102,-699 "/>
|
||||
<text text-anchor="middle" x="129" y="-683.8" font-family="arial" font-size="14.00">25-pin</text>
|
||||
<polyline fill="none" stroke="black" points="0,-676 156,-676 "/>
|
||||
<text text-anchor="middle" x="54.5" y="-660.8" font-family="arial" font-size="14.00">SENSE_P_1</text>
|
||||
<polyline fill="none" stroke="black" points="0,-653 109,-653 "/>
|
||||
<text text-anchor="middle" x="54.5" y="-637.8" font-family="arial" font-size="14.00">SENSE_N_1</text>
|
||||
<polyline fill="none" stroke="black" points="0,-630 109,-630 "/>
|
||||
<text text-anchor="middle" x="54.5" y="-614.8" font-family="arial" font-size="14.00">SENSE_P_2</text>
|
||||
<polyline fill="none" stroke="black" points="0,-607 109,-607 "/>
|
||||
<text text-anchor="middle" x="54.5" y="-591.8" font-family="arial" font-size="14.00">SENSE_N_2</text>
|
||||
<polyline fill="none" stroke="black" points="0,-584 109,-584 "/>
|
||||
<text text-anchor="middle" x="54.5" y="-568.8" font-family="arial" font-size="14.00">SENSE_P_3</text>
|
||||
<polyline fill="none" stroke="black" points="0,-561 109,-561 "/>
|
||||
<text text-anchor="middle" x="54.5" y="-545.8" font-family="arial" font-size="14.00">SENSE_N_3</text>
|
||||
<polyline fill="none" stroke="black" points="0,-538 109,-538 "/>
|
||||
<text text-anchor="middle" x="54.5" y="-522.8" font-family="arial" font-size="14.00">SENSE_P_4</text>
|
||||
<polyline fill="none" stroke="black" points="0,-515 109,-515 "/>
|
||||
<text text-anchor="middle" x="54.5" y="-499.8" font-family="arial" font-size="14.00">SENSE_N_4</text>
|
||||
<polyline fill="none" stroke="black" points="0,-492 109,-492 "/>
|
||||
<text text-anchor="middle" x="54.5" y="-476.8" font-family="arial" font-size="14.00">SENSE_P_5</text>
|
||||
<polyline fill="none" stroke="black" points="0,-469 109,-469 "/>
|
||||
<text text-anchor="middle" x="54.5" y="-453.8" font-family="arial" font-size="14.00">SENSE_N_5</text>
|
||||
<polyline fill="none" stroke="black" points="0,-446 109,-446 "/>
|
||||
<text text-anchor="middle" x="54.5" y="-430.8" font-family="arial" font-size="14.00">SENSE_P_6</text>
|
||||
<polyline fill="none" stroke="black" points="0,-423 109,-423 "/>
|
||||
<text text-anchor="middle" x="54.5" y="-407.8" font-family="arial" font-size="14.00">SENSE_N_6</text>
|
||||
<polyline fill="none" stroke="black" points="0,-400 109,-400 "/>
|
||||
<text text-anchor="middle" x="54.5" y="-384.8" font-family="arial" font-size="14.00">GND</text>
|
||||
<polyline fill="none" stroke="black" points="109,-377 109,-676 "/>
|
||||
<text text-anchor="middle" x="132.5" y="-660.8" font-family="arial" font-size="14.00">1</text>
|
||||
<polyline fill="none" stroke="black" points="109,-653 156,-653 "/>
|
||||
<text text-anchor="middle" x="132.5" y="-637.8" font-family="arial" font-size="14.00">14</text>
|
||||
<polyline fill="none" stroke="black" points="109,-630 156,-630 "/>
|
||||
<text text-anchor="middle" x="132.5" y="-614.8" font-family="arial" font-size="14.00">3</text>
|
||||
<polyline fill="none" stroke="black" points="109,-607 156,-607 "/>
|
||||
<text text-anchor="middle" x="132.5" y="-591.8" font-family="arial" font-size="14.00">16</text>
|
||||
<polyline fill="none" stroke="black" points="109,-584 156,-584 "/>
|
||||
<text text-anchor="middle" x="132.5" y="-568.8" font-family="arial" font-size="14.00">5</text>
|
||||
<polyline fill="none" stroke="black" points="109,-561 156,-561 "/>
|
||||
<text text-anchor="middle" x="132.5" y="-545.8" font-family="arial" font-size="14.00">18</text>
|
||||
<polyline fill="none" stroke="black" points="109,-538 156,-538 "/>
|
||||
<text text-anchor="middle" x="132.5" y="-522.8" font-family="arial" font-size="14.00">7</text>
|
||||
<polyline fill="none" stroke="black" points="109,-515 156,-515 "/>
|
||||
<text text-anchor="middle" x="132.5" y="-499.8" font-family="arial" font-size="14.00">20</text>
|
||||
<polyline fill="none" stroke="black" points="109,-492 156,-492 "/>
|
||||
<text text-anchor="middle" x="132.5" y="-476.8" font-family="arial" font-size="14.00">9</text>
|
||||
<polyline fill="none" stroke="black" points="109,-469 156,-469 "/>
|
||||
<text text-anchor="middle" x="132.5" y="-453.8" font-family="arial" font-size="14.00">22</text>
|
||||
<polyline fill="none" stroke="black" points="109,-446 156,-446 "/>
|
||||
<text text-anchor="middle" x="132.5" y="-430.8" font-family="arial" font-size="14.00">11</text>
|
||||
<polyline fill="none" stroke="black" points="109,-423 156,-423 "/>
|
||||
<text text-anchor="middle" x="132.5" y="-407.8" font-family="arial" font-size="14.00">24</text>
|
||||
<polyline fill="none" stroke="black" points="109,-400 156,-400 "/>
|
||||
<text text-anchor="middle" x="132.5" y="-384.8" font-family="arial" font-size="14.00">13</text>
|
||||
</g>
|
||||
<!-- W1 -->
|
||||
<g id="node3" class="node">
|
||||
<title>W1</title>
|
||||
<polygon fill="none" stroke="black" points="470,-772.5 300,-772.5 300,-348.5 470,-348.5 470,-772.5"/>
|
||||
<polygon fill="none" stroke="black" points="300,-749.5 300,-772.5 470,-772.5 470,-749.5 300,-749.5"/>
|
||||
<text text-anchor="start" x="374" y="-757.3" font-family="arial" font-size="14.00">W1</text>
|
||||
<polygon fill="none" stroke="black" points="300,-726.5 300,-749.5 330,-749.5 330,-726.5 300,-726.5"/>
|
||||
<text text-anchor="start" x="304" y="-734.3" font-family="arial" font-size="14.00">12x</text>
|
||||
<polygon fill="none" stroke="black" points="330,-726.5 330,-749.5 397,-749.5 397,-726.5 330,-726.5"/>
|
||||
<text text-anchor="start" x="334" y="-734.3" font-family="arial" font-size="14.00">0.25 mm²</text>
|
||||
<polygon fill="none" stroke="black" points="397,-726.5 397,-749.5 427,-749.5 427,-726.5 397,-726.5"/>
|
||||
<text text-anchor="start" x="401" y="-734.3" font-family="arial" font-size="14.00">+ S</text>
|
||||
<polygon fill="none" stroke="black" points="427,-726.5 427,-749.5 470,-749.5 470,-726.5 427,-726.5"/>
|
||||
<text text-anchor="start" x="431" y="-734.3" font-family="arial" font-size="14.00">0.2 m</text>
|
||||
<text text-anchor="start" x="383" y="-715.3" font-family="arial" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="309" y="-698.3" font-family="arial" font-size="14.00">X1:14</text>
|
||||
<text text-anchor="start" x="370" y="-698.3" font-family="arial" font-size="14.00">WH</text>
|
||||
<text text-anchor="start" x="422.5" y="-698.3" font-family="arial" font-size="14.00">X2:z2</text>
|
||||
<polygon fill="#ffffff" stroke="transparent" points="300,-686.5 300,-692.5 470,-692.5 470,-686.5 300,-686.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="301,-687.5 469,-687.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="469,-691.5 301,-691.5 "/>
|
||||
<text text-anchor="start" x="313" y="-673.3" font-family="arial" font-size="14.00">X1:1</text>
|
||||
<text text-anchor="start" x="372.5" y="-673.3" font-family="arial" font-size="14.00">BN</text>
|
||||
<text text-anchor="start" x="422" y="-673.3" font-family="arial" font-size="14.00">X2:d4</text>
|
||||
<polygon fill="#666600" stroke="transparent" stroke-width="2" points="300,-661.5 300,-667.5 470,-667.5 470,-661.5 300,-661.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="301,-662.5 469,-662.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="469,-666.5 301,-666.5 "/>
|
||||
<text text-anchor="start" x="309" y="-648.3" font-family="arial" font-size="14.00">X1:16</text>
|
||||
<text text-anchor="start" x="371" y="-648.3" font-family="arial" font-size="14.00">GN</text>
|
||||
<text text-anchor="start" x="422.5" y="-648.3" font-family="arial" font-size="14.00">X2:z8</text>
|
||||
<polygon fill="#00ff00" stroke="transparent" stroke-width="2" points="300,-636.5 300,-642.5 470,-642.5 470,-636.5 300,-636.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="301,-637.5 469,-637.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="469,-641.5 301,-641.5 "/>
|
||||
<text text-anchor="start" x="313" y="-623.3" font-family="arial" font-size="14.00">X1:3</text>
|
||||
<text text-anchor="start" x="372.5" y="-623.3" font-family="arial" font-size="14.00">YE</text>
|
||||
<text text-anchor="start" x="418.5" y="-623.3" font-family="arial" font-size="14.00">X2:d10</text>
|
||||
<polygon fill="#ffff00" stroke="transparent" stroke-width="2" points="300,-611.5 300,-617.5 470,-617.5 470,-611.5 300,-611.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="301,-612.5 469,-612.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="469,-616.5 301,-616.5 "/>
|
||||
<text text-anchor="start" x="309" y="-598.3" font-family="arial" font-size="14.00">X1:18</text>
|
||||
<text text-anchor="start" x="371.5" y="-598.3" font-family="arial" font-size="14.00">GY</text>
|
||||
<text text-anchor="start" x="418.5" y="-598.3" font-family="arial" font-size="14.00">X2:z14</text>
|
||||
<polygon fill="#999999" stroke="transparent" stroke-width="2" points="300,-586.5 300,-592.5 470,-592.5 470,-586.5 300,-586.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="301,-587.5 469,-587.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="469,-591.5 301,-591.5 "/>
|
||||
<text text-anchor="start" x="313" y="-573.3" font-family="arial" font-size="14.00">X1:5</text>
|
||||
<text text-anchor="start" x="372.5" y="-573.3" font-family="arial" font-size="14.00">PK</text>
|
||||
<text text-anchor="start" x="418.5" y="-573.3" font-family="arial" font-size="14.00">X2:d16</text>
|
||||
<polygon fill="#ff66cc" stroke="transparent" stroke-width="2" points="300,-561.5 300,-567.5 470,-567.5 470,-561.5 300,-561.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="301,-562.5 469,-562.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="469,-566.5 301,-566.5 "/>
|
||||
<text text-anchor="start" x="309" y="-548.3" font-family="arial" font-size="14.00">X1:20</text>
|
||||
<text text-anchor="start" x="372.5" y="-548.3" font-family="arial" font-size="14.00">BU</text>
|
||||
<text text-anchor="start" x="418.5" y="-548.3" font-family="arial" font-size="14.00">X2:z18</text>
|
||||
<polygon fill="#0066ff" stroke="transparent" stroke-width="2" points="300,-536.5 300,-542.5 470,-542.5 470,-536.5 300,-536.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="301,-537.5 469,-537.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="469,-541.5 301,-541.5 "/>
|
||||
<text text-anchor="start" x="313" y="-523.3" font-family="arial" font-size="14.00">X1:7</text>
|
||||
<text text-anchor="start" x="372" y="-523.3" font-family="arial" font-size="14.00">RD</text>
|
||||
<text text-anchor="start" x="418.5" y="-523.3" font-family="arial" font-size="14.00">X2:d20</text>
|
||||
<polygon fill="#ff0000" stroke="transparent" stroke-width="2" points="300,-511.5 300,-517.5 470,-517.5 470,-511.5 300,-511.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="301,-512.5 469,-512.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="469,-516.5 301,-516.5 "/>
|
||||
<text text-anchor="start" x="309" y="-498.3" font-family="arial" font-size="14.00">X1:22</text>
|
||||
<text text-anchor="start" x="372.5" y="-498.3" font-family="arial" font-size="14.00">BK</text>
|
||||
<text text-anchor="start" x="418.5" y="-498.3" font-family="arial" font-size="14.00">X2:z24</text>
|
||||
<polygon fill="#000000" stroke="transparent" stroke-width="2" points="300,-486.5 300,-492.5 470,-492.5 470,-486.5 300,-486.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="301,-487.5 469,-487.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="469,-491.5 301,-491.5 "/>
|
||||
<text text-anchor="start" x="313" y="-473.3" font-family="arial" font-size="14.00">X1:9</text>
|
||||
<text text-anchor="start" x="373" y="-473.3" font-family="arial" font-size="14.00">VT</text>
|
||||
<text text-anchor="start" x="418.5" y="-473.3" font-family="arial" font-size="14.00">X2:d26</text>
|
||||
<polygon fill="#8000ff" stroke="transparent" stroke-width="2" points="300,-461.5 300,-467.5 470,-467.5 470,-461.5 300,-461.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="301,-462.5 469,-462.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="469,-466.5 301,-466.5 "/>
|
||||
<text text-anchor="start" x="309" y="-448.3" font-family="arial" font-size="14.00">X1:24</text>
|
||||
<text text-anchor="start" x="370" y="-448.3" font-family="arial" font-size="14.00">WH</text>
|
||||
<text text-anchor="start" x="418.5" y="-448.3" font-family="arial" font-size="14.00">X2:z30</text>
|
||||
<polygon fill="#ffffff" stroke="transparent" stroke-width="2" points="300,-436.5 300,-442.5 470,-442.5 470,-436.5 300,-436.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="301,-437.5 469,-437.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="469,-441.5 301,-441.5 "/>
|
||||
<text text-anchor="start" x="309.5" y="-423.3" font-family="arial" font-size="14.00">X1:11</text>
|
||||
<text text-anchor="start" x="372.5" y="-423.3" font-family="arial" font-size="14.00">BN</text>
|
||||
<text text-anchor="start" x="418.5" y="-423.3" font-family="arial" font-size="14.00">X2:d32</text>
|
||||
<polygon fill="#666600" stroke="transparent" stroke-width="2" points="300,-411.5 300,-417.5 470,-417.5 470,-411.5 300,-411.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="301,-412.5 469,-412.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="469,-416.5 301,-416.5 "/>
|
||||
<text text-anchor="start" x="325" y="-398.3" font-family="arial" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="309" y="-379.3" font-family="arial" font-size="14.00">X1:13</text>
|
||||
<text text-anchor="start" x="363" y="-379.3" font-family="arial" font-size="14.00">Shield</text>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="301,-368.5 469,-368.5 "/>
|
||||
<text text-anchor="start" x="325" y="-354.3" font-family="arial" font-size="14.00"> </text>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-662.5C220,-662.5 236,-662.5 300,-662.5"/>
|
||||
<path fill="none" stroke="#666600" stroke-width="2" d="M156,-664.5C220,-664.5 236,-664.5 300,-664.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-666.5C220,-666.5 236,-666.5 300,-666.5"/>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-639.5C225.43,-641.13 234.5,-689.13 300,-687.5"/>
|
||||
<path fill="none" stroke="#ffffff" stroke-width="2" d="M156,-641.5C223.46,-641.5 232.54,-689.5 300,-689.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-643.5C221.5,-641.87 230.57,-689.87 300,-691.5"/>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-616.5C219.54,-616.56 235.49,-612.56 300,-612.5"/>
|
||||
<path fill="none" stroke="#ffff00" stroke-width="2" d="M156,-618.5C220.02,-618.5 235.98,-614.5 300,-614.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-620.5C220.51,-620.44 236.46,-616.44 300,-616.5"/>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-593.5C224.87,-595.05 235.03,-639.05 300,-637.5"/>
|
||||
<path fill="none" stroke="#00ff00" stroke-width="2" d="M156,-595.5C222.92,-595.5 233.08,-639.5 300,-639.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-597.5C220.97,-595.95 231.13,-639.95 300,-641.5"/>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-570.5C219.2,-570.72 235,-562.72 300,-562.5"/>
|
||||
<path fill="none" stroke="#ff66cc" stroke-width="2" d="M156,-572.5C220.1,-572.5 235.9,-564.5 300,-564.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-574.5C221,-574.28 236.8,-566.28 300,-566.5"/>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-547.5C224.35,-548.96 235.5,-588.96 300,-587.5"/>
|
||||
<path fill="none" stroke="#999999" stroke-width="2" d="M156,-549.5C222.42,-549.5 233.58,-589.5 300,-589.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-551.5C220.5,-550.04 231.65,-590.04 300,-591.5"/>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge13" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-524.5C219,-524.92 234.56,-512.92 300,-512.5"/>
|
||||
<path fill="none" stroke="#ff0000" stroke-width="2" d="M156,-526.5C220.22,-526.5 235.78,-514.5 300,-514.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-528.5C221.44,-528.08 237,-516.08 300,-516.5"/>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge15" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-501.5C223.87,-502.86 235.93,-538.86 300,-537.5"/>
|
||||
<path fill="none" stroke="#0066ff" stroke-width="2" d="M156,-503.5C221.97,-503.5 234.03,-539.5 300,-539.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-505.5C220.07,-504.14 232.13,-540.14 300,-541.5"/>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge17" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-478.5C218.94,-479.12 234.16,-463.12 300,-462.5"/>
|
||||
<path fill="none" stroke="#8000ff" stroke-width="2" d="M156,-480.5C220.39,-480.5 235.61,-464.5 300,-464.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-482.5C221.84,-481.88 237.06,-465.88 300,-466.5"/>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge19" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-455.5C223.42,-456.75 236.29,-488.75 300,-487.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-457.5C221.56,-457.5 234.44,-489.5 300,-489.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-459.5C219.71,-458.25 232.58,-490.25 300,-491.5"/>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge21" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-432.5C219.01,-433.31 233.78,-413.31 300,-412.5"/>
|
||||
<path fill="none" stroke="#666600" stroke-width="2" d="M156,-434.5C220.61,-434.5 235.39,-414.5 300,-414.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-436.5C222.22,-435.69 236.99,-415.69 300,-416.5"/>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge23" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-409.5C223,-410.63 236.6,-438.63 300,-437.5"/>
|
||||
<path fill="none" stroke="#ffffff" stroke-width="2" d="M156,-411.5C221.2,-411.5 234.8,-439.5 300,-439.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-413.5C219.4,-412.37 233,-440.37 300,-441.5"/>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge25" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-388.5C220.5,-388.5 235.5,-370.5 300,-370.5"/>
|
||||
</g>
|
||||
<!-- X2 -->
|
||||
<g id="node2" class="node">
|
||||
<title>X2</title>
|
||||
<polygon fill="white" stroke="black" points="614,-0.5 614,-1150.5 766,-1150.5 766,-0.5 614,-0.5"/>
|
||||
<text text-anchor="middle" x="690" y="-1135.3" font-family="arial" font-size="14.00">X2</text>
|
||||
<polyline fill="none" stroke="black" points="614,-1127.5 766,-1127.5 "/>
|
||||
<text text-anchor="middle" x="634" y="-1112.3" font-family="arial" font-size="14.00">F48</text>
|
||||
<polyline fill="none" stroke="black" points="654,-1104.5 654,-1127.5 "/>
|
||||
<text text-anchor="middle" x="683" y="-1112.3" font-family="arial" font-size="14.00">female</text>
|
||||
<polyline fill="none" stroke="black" points="712,-1104.5 712,-1127.5 "/>
|
||||
<text text-anchor="middle" x="739" y="-1112.3" font-family="arial" font-size="14.00">48-pin</text>
|
||||
<polyline fill="none" stroke="black" points="614,-1104.5 766,-1104.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-1089.3" font-family="arial" font-size="14.00">z2</text>
|
||||
<polyline fill="none" stroke="black" points="614,-1081.5 766,-1081.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-1066.3" font-family="arial" font-size="14.00">b2</text>
|
||||
<polyline fill="none" stroke="black" points="614,-1058.5 766,-1058.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-1043.3" font-family="arial" font-size="14.00">d2</text>
|
||||
<polyline fill="none" stroke="black" points="614,-1035.5 766,-1035.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-1020.3" font-family="arial" font-size="14.00">z4</text>
|
||||
<polyline fill="none" stroke="black" points="614,-1012.5 766,-1012.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-997.3" font-family="arial" font-size="14.00">b4</text>
|
||||
<polyline fill="none" stroke="black" points="614,-989.5 766,-989.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-974.3" font-family="arial" font-size="14.00">d4</text>
|
||||
<polyline fill="none" stroke="black" points="614,-966.5 766,-966.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-951.3" font-family="arial" font-size="14.00">z6</text>
|
||||
<polyline fill="none" stroke="black" points="614,-943.5 766,-943.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-928.3" font-family="arial" font-size="14.00">b6</text>
|
||||
<polyline fill="none" stroke="black" points="614,-920.5 766,-920.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-905.3" font-family="arial" font-size="14.00">d6</text>
|
||||
<polyline fill="none" stroke="black" points="614,-897.5 766,-897.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-882.3" font-family="arial" font-size="14.00">z8</text>
|
||||
<polyline fill="none" stroke="black" points="614,-874.5 766,-874.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-859.3" font-family="arial" font-size="14.00">b8</text>
|
||||
<polyline fill="none" stroke="black" points="614,-851.5 766,-851.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-836.3" font-family="arial" font-size="14.00">d8</text>
|
||||
<polyline fill="none" stroke="black" points="614,-828.5 766,-828.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-813.3" font-family="arial" font-size="14.00">z10</text>
|
||||
<polyline fill="none" stroke="black" points="614,-805.5 766,-805.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-790.3" font-family="arial" font-size="14.00">b10</text>
|
||||
<polyline fill="none" stroke="black" points="614,-782.5 766,-782.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-767.3" font-family="arial" font-size="14.00">d10</text>
|
||||
<polyline fill="none" stroke="black" points="614,-759.5 766,-759.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-744.3" font-family="arial" font-size="14.00">z12</text>
|
||||
<polyline fill="none" stroke="black" points="614,-736.5 766,-736.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-721.3" font-family="arial" font-size="14.00">b12</text>
|
||||
<polyline fill="none" stroke="black" points="614,-713.5 766,-713.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-698.3" font-family="arial" font-size="14.00">d12</text>
|
||||
<polyline fill="none" stroke="black" points="614,-690.5 766,-690.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-675.3" font-family="arial" font-size="14.00">z14</text>
|
||||
<polyline fill="none" stroke="black" points="614,-667.5 766,-667.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-652.3" font-family="arial" font-size="14.00">b14</text>
|
||||
<polyline fill="none" stroke="black" points="614,-644.5 766,-644.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-629.3" font-family="arial" font-size="14.00">d14</text>
|
||||
<polyline fill="none" stroke="black" points="614,-621.5 766,-621.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-606.3" font-family="arial" font-size="14.00">z16</text>
|
||||
<polyline fill="none" stroke="black" points="614,-598.5 766,-598.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-583.3" font-family="arial" font-size="14.00">b16</text>
|
||||
<polyline fill="none" stroke="black" points="614,-575.5 766,-575.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-560.3" font-family="arial" font-size="14.00">d16</text>
|
||||
<polyline fill="none" stroke="black" points="614,-552.5 766,-552.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-537.3" font-family="arial" font-size="14.00">z18</text>
|
||||
<polyline fill="none" stroke="black" points="614,-529.5 766,-529.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-514.3" font-family="arial" font-size="14.00">b18</text>
|
||||
<polyline fill="none" stroke="black" points="614,-506.5 766,-506.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-491.3" font-family="arial" font-size="14.00">d18</text>
|
||||
<polyline fill="none" stroke="black" points="614,-483.5 766,-483.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-468.3" font-family="arial" font-size="14.00">z20</text>
|
||||
<polyline fill="none" stroke="black" points="614,-460.5 766,-460.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-445.3" font-family="arial" font-size="14.00">b20</text>
|
||||
<polyline fill="none" stroke="black" points="614,-437.5 766,-437.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-422.3" font-family="arial" font-size="14.00">d20</text>
|
||||
<polyline fill="none" stroke="black" points="614,-414.5 766,-414.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-399.3" font-family="arial" font-size="14.00">z22</text>
|
||||
<polyline fill="none" stroke="black" points="614,-391.5 766,-391.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-376.3" font-family="arial" font-size="14.00">b22</text>
|
||||
<polyline fill="none" stroke="black" points="614,-368.5 766,-368.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-353.3" font-family="arial" font-size="14.00">d22</text>
|
||||
<polyline fill="none" stroke="black" points="614,-345.5 766,-345.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-330.3" font-family="arial" font-size="14.00">z24</text>
|
||||
<polyline fill="none" stroke="black" points="614,-322.5 766,-322.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-307.3" font-family="arial" font-size="14.00">b24</text>
|
||||
<polyline fill="none" stroke="black" points="614,-299.5 766,-299.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-284.3" font-family="arial" font-size="14.00">d24</text>
|
||||
<polyline fill="none" stroke="black" points="614,-276.5 766,-276.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-261.3" font-family="arial" font-size="14.00">z26</text>
|
||||
<polyline fill="none" stroke="black" points="614,-253.5 766,-253.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-238.3" font-family="arial" font-size="14.00">b26</text>
|
||||
<polyline fill="none" stroke="black" points="614,-230.5 766,-230.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-215.3" font-family="arial" font-size="14.00">d26</text>
|
||||
<polyline fill="none" stroke="black" points="614,-207.5 766,-207.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-192.3" font-family="arial" font-size="14.00">z28</text>
|
||||
<polyline fill="none" stroke="black" points="614,-184.5 766,-184.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-169.3" font-family="arial" font-size="14.00">b28</text>
|
||||
<polyline fill="none" stroke="black" points="614,-161.5 766,-161.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-146.3" font-family="arial" font-size="14.00">d28</text>
|
||||
<polyline fill="none" stroke="black" points="614,-138.5 766,-138.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-123.3" font-family="arial" font-size="14.00">z30</text>
|
||||
<polyline fill="none" stroke="black" points="614,-115.5 766,-115.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-100.3" font-family="arial" font-size="14.00">b30</text>
|
||||
<polyline fill="none" stroke="black" points="614,-92.5 766,-92.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-77.3" font-family="arial" font-size="14.00">d30</text>
|
||||
<polyline fill="none" stroke="black" points="614,-69.5 766,-69.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-54.3" font-family="arial" font-size="14.00">z32</text>
|
||||
<polyline fill="none" stroke="black" points="614,-46.5 766,-46.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-31.3" font-family="arial" font-size="14.00">b32</text>
|
||||
<polyline fill="none" stroke="black" points="614,-23.5 766,-23.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-8.3" font-family="arial" font-size="14.00">d32</text>
|
||||
</g>
|
||||
<!-- W1--X2 -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>W1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-662.5C625.31,-665.42 462.24,-979.42 614,-976.5"/>
|
||||
<path fill="none" stroke="#666600" stroke-width="2" d="M470,-664.5C623.53,-664.5 460.47,-978.5 614,-978.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-666.5C621.76,-663.58 458.69,-977.58 614,-980.5"/>
|
||||
</g>
|
||||
<!-- W1--X2 -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>W1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-687.5C662.35,-690.51 425.1,-1094.51 614,-1091.5"/>
|
||||
<path fill="none" stroke="#ffffff" stroke-width="2" d="M470,-689.5C660.62,-689.5 423.38,-1093.5 614,-1093.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-691.5C658.9,-688.49 421.65,-1092.49 614,-1095.5"/>
|
||||
</g>
|
||||
<!-- W1--X2 -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>W1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-612.5C566.6,-615.06 521.24,-772.06 614,-769.5"/>
|
||||
<path fill="none" stroke="#ffff00" stroke-width="2" d="M470,-614.5C564.68,-614.5 519.32,-771.5 614,-771.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-616.5C562.76,-613.94 517.4,-770.94 614,-773.5"/>
|
||||
</g>
|
||||
<!-- W1--X2 -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>W1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-637.5C598.9,-640.31 488.76,-887.31 614,-884.5"/>
|
||||
<path fill="none" stroke="#00ff00" stroke-width="2" d="M470,-639.5C597.07,-639.5 486.93,-886.5 614,-886.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-641.5C595.24,-638.69 485.1,-885.69 614,-888.5"/>
|
||||
</g>
|
||||
<!-- W1--X2 -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>W1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-562.5C533.88,-562.5 549.87,-561.5 614,-561.5"/>
|
||||
<path fill="none" stroke="#ff66cc" stroke-width="2" d="M470,-564.5C534,-564.5 550,-563.5 614,-563.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-566.5C534.13,-566.5 550.12,-565.5 614,-565.5"/>
|
||||
</g>
|
||||
<!-- W1--X2 -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>W1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-587.5C547.47,-589.65 540.52,-679.65 614,-677.5"/>
|
||||
<path fill="none" stroke="#999999" stroke-width="2" d="M470,-589.5C545.47,-589.5 538.53,-679.5 614,-679.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-591.5C543.48,-589.35 536.53,-679.35 614,-681.5"/>
|
||||
</g>
|
||||
<!-- W1--X2 -->
|
||||
<g id="edge14" class="edge">
|
||||
<title>W1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-512.5C543.24,-514.65 536.77,-425.65 614,-423.5"/>
|
||||
<path fill="none" stroke="#ff0000" stroke-width="2" d="M470,-514.5C545.24,-514.5 538.76,-425.5 614,-425.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-516.5C547.23,-514.35 540.76,-425.35 614,-427.5"/>
|
||||
</g>
|
||||
<!-- W1--X2 -->
|
||||
<g id="edge16" class="edge">
|
||||
<title>W1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-537.5C534.13,-537.5 550.12,-538.5 614,-538.5"/>
|
||||
<path fill="none" stroke="#0066ff" stroke-width="2" d="M470,-539.5C534,-539.5 550,-540.5 614,-540.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-541.5C533.88,-541.5 549.87,-542.5 614,-542.5"/>
|
||||
</g>
|
||||
<!-- W1--X2 -->
|
||||
<g id="edge18" class="edge">
|
||||
<title>W1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-462.5C594.86,-465.31 485.48,-219.31 614,-216.5"/>
|
||||
<path fill="none" stroke="#8000ff" stroke-width="2" d="M470,-464.5C596.69,-464.5 487.31,-218.5 614,-218.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-466.5C598.52,-463.69 489.14,-217.69 614,-220.5"/>
|
||||
</g>
|
||||
<!-- W1--X2 -->
|
||||
<g id="edge20" class="edge">
|
||||
<title>W1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-487.5C562.43,-490.05 517.72,-334.05 614,-331.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-489.5C564.36,-489.5 519.64,-333.5 614,-333.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-491.5C566.28,-488.95 521.57,-332.95 614,-335.5"/>
|
||||
</g>
|
||||
<!-- W1--X2 -->
|
||||
<g id="edge22" class="edge">
|
||||
<title>W1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-412.5C658.48,-415.51 422.07,-12.51 614,-9.5"/>
|
||||
<path fill="none" stroke="#666600" stroke-width="2" d="M470,-414.5C660.2,-414.5 423.8,-11.5 614,-11.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-416.5C661.93,-413.49 425.52,-10.49 614,-13.5"/>
|
||||
</g>
|
||||
<!-- W1--X2 -->
|
||||
<g id="edge24" class="edge">
|
||||
<title>W1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-437.5C621.35,-440.42 459.1,-127.42 614,-124.5"/>
|
||||
<path fill="none" stroke="#ffffff" stroke-width="2" d="M470,-439.5C623.13,-439.5 460.87,-126.5 614,-126.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-441.5C624.9,-438.58 462.65,-125.58 614,-128.5"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<h1>Bill of Materials</h1><table style="border:1px solid #000000; font-size: 14pt; border-spacing: 0px"><tr><th align="left" style="border:1px solid #000000; padding: 8px">Item</th><th align="left" style="border:1px solid #000000; padding: 8px">Qty</th><th align="left" style="border:1px solid #000000; padding: 8px">Unit</th><th align="left" style="border:1px solid #000000; padding: 8px">Designators</th></tr><tr><td style="border:1px solid #000000; padding: 4px">Connector, D-Sub, male, 25 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">1</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X1</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Connector, F48, female, 48 pins</td><td align="right" style="border:1px solid #000000; padding: 4px">1</td><td style="border:1px solid #000000; padding: 4px"></td><td style="border:1px solid #000000; padding: 4px">X2</td></tr><tr><td style="border:1px solid #000000; padding: 4px">Cable, 12 x 0.25 mm² shielded</td><td align="right" style="border:1px solid #000000; padding: 4px">0.2</td><td style="border:1px solid #000000; padding: 4px">m</td><td style="border:1px solid #000000; padding: 4px">W1</td></tr></table></body></html>
|
||||
BIN
examples/ex09.png
Normal file
|
After Width: | Height: | Size: 203 KiB |
450
examples/ex09.svg
Normal file
@ -0,0 +1,450 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.44.0 (20200408.0750)
|
||||
-->
|
||||
<!-- Pages: 1 -->
|
||||
<svg width="774pt" height="1159pt"
|
||||
viewBox="0.00 0.00 774.00 1159.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 1155)">
|
||||
<polygon fill="white" stroke="transparent" points="-4,4 -4,-1155 770,-1155 770,4 -4,4"/>
|
||||
<!-- X1 -->
|
||||
<g id="node1" class="node">
|
||||
<title>X1</title>
|
||||
<polygon fill="white" stroke="black" points="0,-377 0,-722 156,-722 156,-377 0,-377"/>
|
||||
<text text-anchor="middle" x="78" y="-706.8" font-family="arial" font-size="14.00">X1</text>
|
||||
<polyline fill="none" stroke="black" points="0,-699 156,-699 "/>
|
||||
<text text-anchor="middle" x="27.5" y="-683.8" font-family="arial" font-size="14.00">D-Sub</text>
|
||||
<polyline fill="none" stroke="black" points="55,-676 55,-699 "/>
|
||||
<text text-anchor="middle" x="78.5" y="-683.8" font-family="arial" font-size="14.00">male</text>
|
||||
<polyline fill="none" stroke="black" points="102,-676 102,-699 "/>
|
||||
<text text-anchor="middle" x="129" y="-683.8" font-family="arial" font-size="14.00">25-pin</text>
|
||||
<polyline fill="none" stroke="black" points="0,-676 156,-676 "/>
|
||||
<text text-anchor="middle" x="54.5" y="-660.8" font-family="arial" font-size="14.00">SENSE_P_1</text>
|
||||
<polyline fill="none" stroke="black" points="0,-653 109,-653 "/>
|
||||
<text text-anchor="middle" x="54.5" y="-637.8" font-family="arial" font-size="14.00">SENSE_N_1</text>
|
||||
<polyline fill="none" stroke="black" points="0,-630 109,-630 "/>
|
||||
<text text-anchor="middle" x="54.5" y="-614.8" font-family="arial" font-size="14.00">SENSE_P_2</text>
|
||||
<polyline fill="none" stroke="black" points="0,-607 109,-607 "/>
|
||||
<text text-anchor="middle" x="54.5" y="-591.8" font-family="arial" font-size="14.00">SENSE_N_2</text>
|
||||
<polyline fill="none" stroke="black" points="0,-584 109,-584 "/>
|
||||
<text text-anchor="middle" x="54.5" y="-568.8" font-family="arial" font-size="14.00">SENSE_P_3</text>
|
||||
<polyline fill="none" stroke="black" points="0,-561 109,-561 "/>
|
||||
<text text-anchor="middle" x="54.5" y="-545.8" font-family="arial" font-size="14.00">SENSE_N_3</text>
|
||||
<polyline fill="none" stroke="black" points="0,-538 109,-538 "/>
|
||||
<text text-anchor="middle" x="54.5" y="-522.8" font-family="arial" font-size="14.00">SENSE_P_4</text>
|
||||
<polyline fill="none" stroke="black" points="0,-515 109,-515 "/>
|
||||
<text text-anchor="middle" x="54.5" y="-499.8" font-family="arial" font-size="14.00">SENSE_N_4</text>
|
||||
<polyline fill="none" stroke="black" points="0,-492 109,-492 "/>
|
||||
<text text-anchor="middle" x="54.5" y="-476.8" font-family="arial" font-size="14.00">SENSE_P_5</text>
|
||||
<polyline fill="none" stroke="black" points="0,-469 109,-469 "/>
|
||||
<text text-anchor="middle" x="54.5" y="-453.8" font-family="arial" font-size="14.00">SENSE_N_5</text>
|
||||
<polyline fill="none" stroke="black" points="0,-446 109,-446 "/>
|
||||
<text text-anchor="middle" x="54.5" y="-430.8" font-family="arial" font-size="14.00">SENSE_P_6</text>
|
||||
<polyline fill="none" stroke="black" points="0,-423 109,-423 "/>
|
||||
<text text-anchor="middle" x="54.5" y="-407.8" font-family="arial" font-size="14.00">SENSE_N_6</text>
|
||||
<polyline fill="none" stroke="black" points="0,-400 109,-400 "/>
|
||||
<text text-anchor="middle" x="54.5" y="-384.8" font-family="arial" font-size="14.00">GND</text>
|
||||
<polyline fill="none" stroke="black" points="109,-377 109,-676 "/>
|
||||
<text text-anchor="middle" x="132.5" y="-660.8" font-family="arial" font-size="14.00">1</text>
|
||||
<polyline fill="none" stroke="black" points="109,-653 156,-653 "/>
|
||||
<text text-anchor="middle" x="132.5" y="-637.8" font-family="arial" font-size="14.00">14</text>
|
||||
<polyline fill="none" stroke="black" points="109,-630 156,-630 "/>
|
||||
<text text-anchor="middle" x="132.5" y="-614.8" font-family="arial" font-size="14.00">3</text>
|
||||
<polyline fill="none" stroke="black" points="109,-607 156,-607 "/>
|
||||
<text text-anchor="middle" x="132.5" y="-591.8" font-family="arial" font-size="14.00">16</text>
|
||||
<polyline fill="none" stroke="black" points="109,-584 156,-584 "/>
|
||||
<text text-anchor="middle" x="132.5" y="-568.8" font-family="arial" font-size="14.00">5</text>
|
||||
<polyline fill="none" stroke="black" points="109,-561 156,-561 "/>
|
||||
<text text-anchor="middle" x="132.5" y="-545.8" font-family="arial" font-size="14.00">18</text>
|
||||
<polyline fill="none" stroke="black" points="109,-538 156,-538 "/>
|
||||
<text text-anchor="middle" x="132.5" y="-522.8" font-family="arial" font-size="14.00">7</text>
|
||||
<polyline fill="none" stroke="black" points="109,-515 156,-515 "/>
|
||||
<text text-anchor="middle" x="132.5" y="-499.8" font-family="arial" font-size="14.00">20</text>
|
||||
<polyline fill="none" stroke="black" points="109,-492 156,-492 "/>
|
||||
<text text-anchor="middle" x="132.5" y="-476.8" font-family="arial" font-size="14.00">9</text>
|
||||
<polyline fill="none" stroke="black" points="109,-469 156,-469 "/>
|
||||
<text text-anchor="middle" x="132.5" y="-453.8" font-family="arial" font-size="14.00">22</text>
|
||||
<polyline fill="none" stroke="black" points="109,-446 156,-446 "/>
|
||||
<text text-anchor="middle" x="132.5" y="-430.8" font-family="arial" font-size="14.00">11</text>
|
||||
<polyline fill="none" stroke="black" points="109,-423 156,-423 "/>
|
||||
<text text-anchor="middle" x="132.5" y="-407.8" font-family="arial" font-size="14.00">24</text>
|
||||
<polyline fill="none" stroke="black" points="109,-400 156,-400 "/>
|
||||
<text text-anchor="middle" x="132.5" y="-384.8" font-family="arial" font-size="14.00">13</text>
|
||||
</g>
|
||||
<!-- W1 -->
|
||||
<g id="node3" class="node">
|
||||
<title>W1</title>
|
||||
<polygon fill="none" stroke="black" points="470,-772.5 300,-772.5 300,-348.5 470,-348.5 470,-772.5"/>
|
||||
<polygon fill="none" stroke="black" points="300,-749.5 300,-772.5 470,-772.5 470,-749.5 300,-749.5"/>
|
||||
<text text-anchor="start" x="374" y="-757.3" font-family="arial" font-size="14.00">W1</text>
|
||||
<polygon fill="none" stroke="black" points="300,-726.5 300,-749.5 330,-749.5 330,-726.5 300,-726.5"/>
|
||||
<text text-anchor="start" x="304" y="-734.3" font-family="arial" font-size="14.00">12x</text>
|
||||
<polygon fill="none" stroke="black" points="330,-726.5 330,-749.5 397,-749.5 397,-726.5 330,-726.5"/>
|
||||
<text text-anchor="start" x="334" y="-734.3" font-family="arial" font-size="14.00">0.25 mm²</text>
|
||||
<polygon fill="none" stroke="black" points="397,-726.5 397,-749.5 427,-749.5 427,-726.5 397,-726.5"/>
|
||||
<text text-anchor="start" x="401" y="-734.3" font-family="arial" font-size="14.00">+ S</text>
|
||||
<polygon fill="none" stroke="black" points="427,-726.5 427,-749.5 470,-749.5 470,-726.5 427,-726.5"/>
|
||||
<text text-anchor="start" x="431" y="-734.3" font-family="arial" font-size="14.00">0.2 m</text>
|
||||
<text text-anchor="start" x="383" y="-715.3" font-family="arial" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="309" y="-698.3" font-family="arial" font-size="14.00">X1:14</text>
|
||||
<text text-anchor="start" x="370" y="-698.3" font-family="arial" font-size="14.00">WH</text>
|
||||
<text text-anchor="start" x="422.5" y="-698.3" font-family="arial" font-size="14.00">X2:z2</text>
|
||||
<polygon fill="#ffffff" stroke="transparent" points="300,-686.5 300,-692.5 470,-692.5 470,-686.5 300,-686.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="301,-687.5 469,-687.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="469,-691.5 301,-691.5 "/>
|
||||
<text text-anchor="start" x="313" y="-673.3" font-family="arial" font-size="14.00">X1:1</text>
|
||||
<text text-anchor="start" x="372.5" y="-673.3" font-family="arial" font-size="14.00">BN</text>
|
||||
<text text-anchor="start" x="422" y="-673.3" font-family="arial" font-size="14.00">X2:d4</text>
|
||||
<polygon fill="#666600" stroke="transparent" stroke-width="2" points="300,-661.5 300,-667.5 470,-667.5 470,-661.5 300,-661.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="301,-662.5 469,-662.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="469,-666.5 301,-666.5 "/>
|
||||
<text text-anchor="start" x="309" y="-648.3" font-family="arial" font-size="14.00">X1:16</text>
|
||||
<text text-anchor="start" x="371" y="-648.3" font-family="arial" font-size="14.00">GN</text>
|
||||
<text text-anchor="start" x="422.5" y="-648.3" font-family="arial" font-size="14.00">X2:z8</text>
|
||||
<polygon fill="#00ff00" stroke="transparent" stroke-width="2" points="300,-636.5 300,-642.5 470,-642.5 470,-636.5 300,-636.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="301,-637.5 469,-637.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="469,-641.5 301,-641.5 "/>
|
||||
<text text-anchor="start" x="313" y="-623.3" font-family="arial" font-size="14.00">X1:3</text>
|
||||
<text text-anchor="start" x="372.5" y="-623.3" font-family="arial" font-size="14.00">YE</text>
|
||||
<text text-anchor="start" x="418.5" y="-623.3" font-family="arial" font-size="14.00">X2:d10</text>
|
||||
<polygon fill="#ffff00" stroke="transparent" stroke-width="2" points="300,-611.5 300,-617.5 470,-617.5 470,-611.5 300,-611.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="301,-612.5 469,-612.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="469,-616.5 301,-616.5 "/>
|
||||
<text text-anchor="start" x="309" y="-598.3" font-family="arial" font-size="14.00">X1:18</text>
|
||||
<text text-anchor="start" x="371.5" y="-598.3" font-family="arial" font-size="14.00">GY</text>
|
||||
<text text-anchor="start" x="418.5" y="-598.3" font-family="arial" font-size="14.00">X2:z14</text>
|
||||
<polygon fill="#999999" stroke="transparent" stroke-width="2" points="300,-586.5 300,-592.5 470,-592.5 470,-586.5 300,-586.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="301,-587.5 469,-587.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="469,-591.5 301,-591.5 "/>
|
||||
<text text-anchor="start" x="313" y="-573.3" font-family="arial" font-size="14.00">X1:5</text>
|
||||
<text text-anchor="start" x="372.5" y="-573.3" font-family="arial" font-size="14.00">PK</text>
|
||||
<text text-anchor="start" x="418.5" y="-573.3" font-family="arial" font-size="14.00">X2:d16</text>
|
||||
<polygon fill="#ff66cc" stroke="transparent" stroke-width="2" points="300,-561.5 300,-567.5 470,-567.5 470,-561.5 300,-561.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="301,-562.5 469,-562.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="469,-566.5 301,-566.5 "/>
|
||||
<text text-anchor="start" x="309" y="-548.3" font-family="arial" font-size="14.00">X1:20</text>
|
||||
<text text-anchor="start" x="372.5" y="-548.3" font-family="arial" font-size="14.00">BU</text>
|
||||
<text text-anchor="start" x="418.5" y="-548.3" font-family="arial" font-size="14.00">X2:z18</text>
|
||||
<polygon fill="#0066ff" stroke="transparent" stroke-width="2" points="300,-536.5 300,-542.5 470,-542.5 470,-536.5 300,-536.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="301,-537.5 469,-537.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="469,-541.5 301,-541.5 "/>
|
||||
<text text-anchor="start" x="313" y="-523.3" font-family="arial" font-size="14.00">X1:7</text>
|
||||
<text text-anchor="start" x="372" y="-523.3" font-family="arial" font-size="14.00">RD</text>
|
||||
<text text-anchor="start" x="418.5" y="-523.3" font-family="arial" font-size="14.00">X2:d20</text>
|
||||
<polygon fill="#ff0000" stroke="transparent" stroke-width="2" points="300,-511.5 300,-517.5 470,-517.5 470,-511.5 300,-511.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="301,-512.5 469,-512.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="469,-516.5 301,-516.5 "/>
|
||||
<text text-anchor="start" x="309" y="-498.3" font-family="arial" font-size="14.00">X1:22</text>
|
||||
<text text-anchor="start" x="372.5" y="-498.3" font-family="arial" font-size="14.00">BK</text>
|
||||
<text text-anchor="start" x="418.5" y="-498.3" font-family="arial" font-size="14.00">X2:z24</text>
|
||||
<polygon fill="#000000" stroke="transparent" stroke-width="2" points="300,-486.5 300,-492.5 470,-492.5 470,-486.5 300,-486.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="301,-487.5 469,-487.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="469,-491.5 301,-491.5 "/>
|
||||
<text text-anchor="start" x="313" y="-473.3" font-family="arial" font-size="14.00">X1:9</text>
|
||||
<text text-anchor="start" x="373" y="-473.3" font-family="arial" font-size="14.00">VT</text>
|
||||
<text text-anchor="start" x="418.5" y="-473.3" font-family="arial" font-size="14.00">X2:d26</text>
|
||||
<polygon fill="#8000ff" stroke="transparent" stroke-width="2" points="300,-461.5 300,-467.5 470,-467.5 470,-461.5 300,-461.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="301,-462.5 469,-462.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="469,-466.5 301,-466.5 "/>
|
||||
<text text-anchor="start" x="309" y="-448.3" font-family="arial" font-size="14.00">X1:24</text>
|
||||
<text text-anchor="start" x="370" y="-448.3" font-family="arial" font-size="14.00">WH</text>
|
||||
<text text-anchor="start" x="418.5" y="-448.3" font-family="arial" font-size="14.00">X2:z30</text>
|
||||
<polygon fill="#ffffff" stroke="transparent" stroke-width="2" points="300,-436.5 300,-442.5 470,-442.5 470,-436.5 300,-436.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="301,-437.5 469,-437.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="469,-441.5 301,-441.5 "/>
|
||||
<text text-anchor="start" x="309.5" y="-423.3" font-family="arial" font-size="14.00">X1:11</text>
|
||||
<text text-anchor="start" x="372.5" y="-423.3" font-family="arial" font-size="14.00">BN</text>
|
||||
<text text-anchor="start" x="418.5" y="-423.3" font-family="arial" font-size="14.00">X2:d32</text>
|
||||
<polygon fill="#666600" stroke="transparent" stroke-width="2" points="300,-411.5 300,-417.5 470,-417.5 470,-411.5 300,-411.5"/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="301,-412.5 469,-412.5 "/>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="469,-416.5 301,-416.5 "/>
|
||||
<text text-anchor="start" x="325" y="-398.3" font-family="arial" font-size="14.00"> </text>
|
||||
<text text-anchor="start" x="309" y="-379.3" font-family="arial" font-size="14.00">X1:13</text>
|
||||
<text text-anchor="start" x="363" y="-379.3" font-family="arial" font-size="14.00">Shield</text>
|
||||
<polyline fill="none" stroke="black" stroke-width="2" points="301,-368.5 469,-368.5 "/>
|
||||
<text text-anchor="start" x="325" y="-354.3" font-family="arial" font-size="14.00"> </text>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-662.5C220,-662.5 236,-662.5 300,-662.5"/>
|
||||
<path fill="none" stroke="#666600" stroke-width="2" d="M156,-664.5C220,-664.5 236,-664.5 300,-664.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-666.5C220,-666.5 236,-666.5 300,-666.5"/>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-639.5C225.43,-641.13 234.5,-689.13 300,-687.5"/>
|
||||
<path fill="none" stroke="#ffffff" stroke-width="2" d="M156,-641.5C223.46,-641.5 232.54,-689.5 300,-689.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-643.5C221.5,-641.87 230.57,-689.87 300,-691.5"/>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-616.5C219.54,-616.56 235.49,-612.56 300,-612.5"/>
|
||||
<path fill="none" stroke="#ffff00" stroke-width="2" d="M156,-618.5C220.02,-618.5 235.98,-614.5 300,-614.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-620.5C220.51,-620.44 236.46,-616.44 300,-616.5"/>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-593.5C224.87,-595.05 235.03,-639.05 300,-637.5"/>
|
||||
<path fill="none" stroke="#00ff00" stroke-width="2" d="M156,-595.5C222.92,-595.5 233.08,-639.5 300,-639.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-597.5C220.97,-595.95 231.13,-639.95 300,-641.5"/>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-570.5C219.2,-570.72 235,-562.72 300,-562.5"/>
|
||||
<path fill="none" stroke="#ff66cc" stroke-width="2" d="M156,-572.5C220.1,-572.5 235.9,-564.5 300,-564.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-574.5C221,-574.28 236.8,-566.28 300,-566.5"/>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-547.5C224.35,-548.96 235.5,-588.96 300,-587.5"/>
|
||||
<path fill="none" stroke="#999999" stroke-width="2" d="M156,-549.5C222.42,-549.5 233.58,-589.5 300,-589.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-551.5C220.5,-550.04 231.65,-590.04 300,-591.5"/>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge13" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-524.5C219,-524.92 234.56,-512.92 300,-512.5"/>
|
||||
<path fill="none" stroke="#ff0000" stroke-width="2" d="M156,-526.5C220.22,-526.5 235.78,-514.5 300,-514.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-528.5C221.44,-528.08 237,-516.08 300,-516.5"/>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge15" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-501.5C223.87,-502.86 235.93,-538.86 300,-537.5"/>
|
||||
<path fill="none" stroke="#0066ff" stroke-width="2" d="M156,-503.5C221.97,-503.5 234.03,-539.5 300,-539.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-505.5C220.07,-504.14 232.13,-540.14 300,-541.5"/>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge17" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-478.5C218.94,-479.12 234.16,-463.12 300,-462.5"/>
|
||||
<path fill="none" stroke="#8000ff" stroke-width="2" d="M156,-480.5C220.39,-480.5 235.61,-464.5 300,-464.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-482.5C221.84,-481.88 237.06,-465.88 300,-466.5"/>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge19" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-455.5C223.42,-456.75 236.29,-488.75 300,-487.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-457.5C221.56,-457.5 234.44,-489.5 300,-489.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-459.5C219.71,-458.25 232.58,-490.25 300,-491.5"/>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge21" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-432.5C219.01,-433.31 233.78,-413.31 300,-412.5"/>
|
||||
<path fill="none" stroke="#666600" stroke-width="2" d="M156,-434.5C220.61,-434.5 235.39,-414.5 300,-414.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-436.5C222.22,-435.69 236.99,-415.69 300,-416.5"/>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge23" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-409.5C223,-410.63 236.6,-438.63 300,-437.5"/>
|
||||
<path fill="none" stroke="#ffffff" stroke-width="2" d="M156,-411.5C221.2,-411.5 234.8,-439.5 300,-439.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-413.5C219.4,-412.37 233,-440.37 300,-441.5"/>
|
||||
</g>
|
||||
<!-- X1--W1 -->
|
||||
<g id="edge25" class="edge">
|
||||
<title>X1:e--W1:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M156,-388.5C220.5,-388.5 235.5,-370.5 300,-370.5"/>
|
||||
</g>
|
||||
<!-- X2 -->
|
||||
<g id="node2" class="node">
|
||||
<title>X2</title>
|
||||
<polygon fill="white" stroke="black" points="614,-0.5 614,-1150.5 766,-1150.5 766,-0.5 614,-0.5"/>
|
||||
<text text-anchor="middle" x="690" y="-1135.3" font-family="arial" font-size="14.00">X2</text>
|
||||
<polyline fill="none" stroke="black" points="614,-1127.5 766,-1127.5 "/>
|
||||
<text text-anchor="middle" x="634" y="-1112.3" font-family="arial" font-size="14.00">F48</text>
|
||||
<polyline fill="none" stroke="black" points="654,-1104.5 654,-1127.5 "/>
|
||||
<text text-anchor="middle" x="683" y="-1112.3" font-family="arial" font-size="14.00">female</text>
|
||||
<polyline fill="none" stroke="black" points="712,-1104.5 712,-1127.5 "/>
|
||||
<text text-anchor="middle" x="739" y="-1112.3" font-family="arial" font-size="14.00">48-pin</text>
|
||||
<polyline fill="none" stroke="black" points="614,-1104.5 766,-1104.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-1089.3" font-family="arial" font-size="14.00">z2</text>
|
||||
<polyline fill="none" stroke="black" points="614,-1081.5 766,-1081.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-1066.3" font-family="arial" font-size="14.00">b2</text>
|
||||
<polyline fill="none" stroke="black" points="614,-1058.5 766,-1058.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-1043.3" font-family="arial" font-size="14.00">d2</text>
|
||||
<polyline fill="none" stroke="black" points="614,-1035.5 766,-1035.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-1020.3" font-family="arial" font-size="14.00">z4</text>
|
||||
<polyline fill="none" stroke="black" points="614,-1012.5 766,-1012.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-997.3" font-family="arial" font-size="14.00">b4</text>
|
||||
<polyline fill="none" stroke="black" points="614,-989.5 766,-989.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-974.3" font-family="arial" font-size="14.00">d4</text>
|
||||
<polyline fill="none" stroke="black" points="614,-966.5 766,-966.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-951.3" font-family="arial" font-size="14.00">z6</text>
|
||||
<polyline fill="none" stroke="black" points="614,-943.5 766,-943.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-928.3" font-family="arial" font-size="14.00">b6</text>
|
||||
<polyline fill="none" stroke="black" points="614,-920.5 766,-920.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-905.3" font-family="arial" font-size="14.00">d6</text>
|
||||
<polyline fill="none" stroke="black" points="614,-897.5 766,-897.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-882.3" font-family="arial" font-size="14.00">z8</text>
|
||||
<polyline fill="none" stroke="black" points="614,-874.5 766,-874.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-859.3" font-family="arial" font-size="14.00">b8</text>
|
||||
<polyline fill="none" stroke="black" points="614,-851.5 766,-851.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-836.3" font-family="arial" font-size="14.00">d8</text>
|
||||
<polyline fill="none" stroke="black" points="614,-828.5 766,-828.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-813.3" font-family="arial" font-size="14.00">z10</text>
|
||||
<polyline fill="none" stroke="black" points="614,-805.5 766,-805.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-790.3" font-family="arial" font-size="14.00">b10</text>
|
||||
<polyline fill="none" stroke="black" points="614,-782.5 766,-782.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-767.3" font-family="arial" font-size="14.00">d10</text>
|
||||
<polyline fill="none" stroke="black" points="614,-759.5 766,-759.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-744.3" font-family="arial" font-size="14.00">z12</text>
|
||||
<polyline fill="none" stroke="black" points="614,-736.5 766,-736.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-721.3" font-family="arial" font-size="14.00">b12</text>
|
||||
<polyline fill="none" stroke="black" points="614,-713.5 766,-713.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-698.3" font-family="arial" font-size="14.00">d12</text>
|
||||
<polyline fill="none" stroke="black" points="614,-690.5 766,-690.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-675.3" font-family="arial" font-size="14.00">z14</text>
|
||||
<polyline fill="none" stroke="black" points="614,-667.5 766,-667.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-652.3" font-family="arial" font-size="14.00">b14</text>
|
||||
<polyline fill="none" stroke="black" points="614,-644.5 766,-644.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-629.3" font-family="arial" font-size="14.00">d14</text>
|
||||
<polyline fill="none" stroke="black" points="614,-621.5 766,-621.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-606.3" font-family="arial" font-size="14.00">z16</text>
|
||||
<polyline fill="none" stroke="black" points="614,-598.5 766,-598.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-583.3" font-family="arial" font-size="14.00">b16</text>
|
||||
<polyline fill="none" stroke="black" points="614,-575.5 766,-575.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-560.3" font-family="arial" font-size="14.00">d16</text>
|
||||
<polyline fill="none" stroke="black" points="614,-552.5 766,-552.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-537.3" font-family="arial" font-size="14.00">z18</text>
|
||||
<polyline fill="none" stroke="black" points="614,-529.5 766,-529.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-514.3" font-family="arial" font-size="14.00">b18</text>
|
||||
<polyline fill="none" stroke="black" points="614,-506.5 766,-506.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-491.3" font-family="arial" font-size="14.00">d18</text>
|
||||
<polyline fill="none" stroke="black" points="614,-483.5 766,-483.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-468.3" font-family="arial" font-size="14.00">z20</text>
|
||||
<polyline fill="none" stroke="black" points="614,-460.5 766,-460.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-445.3" font-family="arial" font-size="14.00">b20</text>
|
||||
<polyline fill="none" stroke="black" points="614,-437.5 766,-437.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-422.3" font-family="arial" font-size="14.00">d20</text>
|
||||
<polyline fill="none" stroke="black" points="614,-414.5 766,-414.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-399.3" font-family="arial" font-size="14.00">z22</text>
|
||||
<polyline fill="none" stroke="black" points="614,-391.5 766,-391.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-376.3" font-family="arial" font-size="14.00">b22</text>
|
||||
<polyline fill="none" stroke="black" points="614,-368.5 766,-368.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-353.3" font-family="arial" font-size="14.00">d22</text>
|
||||
<polyline fill="none" stroke="black" points="614,-345.5 766,-345.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-330.3" font-family="arial" font-size="14.00">z24</text>
|
||||
<polyline fill="none" stroke="black" points="614,-322.5 766,-322.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-307.3" font-family="arial" font-size="14.00">b24</text>
|
||||
<polyline fill="none" stroke="black" points="614,-299.5 766,-299.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-284.3" font-family="arial" font-size="14.00">d24</text>
|
||||
<polyline fill="none" stroke="black" points="614,-276.5 766,-276.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-261.3" font-family="arial" font-size="14.00">z26</text>
|
||||
<polyline fill="none" stroke="black" points="614,-253.5 766,-253.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-238.3" font-family="arial" font-size="14.00">b26</text>
|
||||
<polyline fill="none" stroke="black" points="614,-230.5 766,-230.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-215.3" font-family="arial" font-size="14.00">d26</text>
|
||||
<polyline fill="none" stroke="black" points="614,-207.5 766,-207.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-192.3" font-family="arial" font-size="14.00">z28</text>
|
||||
<polyline fill="none" stroke="black" points="614,-184.5 766,-184.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-169.3" font-family="arial" font-size="14.00">b28</text>
|
||||
<polyline fill="none" stroke="black" points="614,-161.5 766,-161.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-146.3" font-family="arial" font-size="14.00">d28</text>
|
||||
<polyline fill="none" stroke="black" points="614,-138.5 766,-138.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-123.3" font-family="arial" font-size="14.00">z30</text>
|
||||
<polyline fill="none" stroke="black" points="614,-115.5 766,-115.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-100.3" font-family="arial" font-size="14.00">b30</text>
|
||||
<polyline fill="none" stroke="black" points="614,-92.5 766,-92.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-77.3" font-family="arial" font-size="14.00">d30</text>
|
||||
<polyline fill="none" stroke="black" points="614,-69.5 766,-69.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-54.3" font-family="arial" font-size="14.00">z32</text>
|
||||
<polyline fill="none" stroke="black" points="614,-46.5 766,-46.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-31.3" font-family="arial" font-size="14.00">b32</text>
|
||||
<polyline fill="none" stroke="black" points="614,-23.5 766,-23.5 "/>
|
||||
<text text-anchor="middle" x="690" y="-8.3" font-family="arial" font-size="14.00">d32</text>
|
||||
</g>
|
||||
<!-- W1--X2 -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>W1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-662.5C625.31,-665.42 462.24,-979.42 614,-976.5"/>
|
||||
<path fill="none" stroke="#666600" stroke-width="2" d="M470,-664.5C623.53,-664.5 460.47,-978.5 614,-978.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-666.5C621.76,-663.58 458.69,-977.58 614,-980.5"/>
|
||||
</g>
|
||||
<!-- W1--X2 -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>W1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-687.5C662.35,-690.51 425.1,-1094.51 614,-1091.5"/>
|
||||
<path fill="none" stroke="#ffffff" stroke-width="2" d="M470,-689.5C660.62,-689.5 423.38,-1093.5 614,-1093.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-691.5C658.9,-688.49 421.65,-1092.49 614,-1095.5"/>
|
||||
</g>
|
||||
<!-- W1--X2 -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>W1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-612.5C566.6,-615.06 521.24,-772.06 614,-769.5"/>
|
||||
<path fill="none" stroke="#ffff00" stroke-width="2" d="M470,-614.5C564.68,-614.5 519.32,-771.5 614,-771.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-616.5C562.76,-613.94 517.4,-770.94 614,-773.5"/>
|
||||
</g>
|
||||
<!-- W1--X2 -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>W1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-637.5C598.9,-640.31 488.76,-887.31 614,-884.5"/>
|
||||
<path fill="none" stroke="#00ff00" stroke-width="2" d="M470,-639.5C597.07,-639.5 486.93,-886.5 614,-886.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-641.5C595.24,-638.69 485.1,-885.69 614,-888.5"/>
|
||||
</g>
|
||||
<!-- W1--X2 -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>W1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-562.5C533.88,-562.5 549.87,-561.5 614,-561.5"/>
|
||||
<path fill="none" stroke="#ff66cc" stroke-width="2" d="M470,-564.5C534,-564.5 550,-563.5 614,-563.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-566.5C534.13,-566.5 550.12,-565.5 614,-565.5"/>
|
||||
</g>
|
||||
<!-- W1--X2 -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>W1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-587.5C547.47,-589.65 540.52,-679.65 614,-677.5"/>
|
||||
<path fill="none" stroke="#999999" stroke-width="2" d="M470,-589.5C545.47,-589.5 538.53,-679.5 614,-679.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-591.5C543.48,-589.35 536.53,-679.35 614,-681.5"/>
|
||||
</g>
|
||||
<!-- W1--X2 -->
|
||||
<g id="edge14" class="edge">
|
||||
<title>W1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-512.5C543.24,-514.65 536.77,-425.65 614,-423.5"/>
|
||||
<path fill="none" stroke="#ff0000" stroke-width="2" d="M470,-514.5C545.24,-514.5 538.76,-425.5 614,-425.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-516.5C547.23,-514.35 540.76,-425.35 614,-427.5"/>
|
||||
</g>
|
||||
<!-- W1--X2 -->
|
||||
<g id="edge16" class="edge">
|
||||
<title>W1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-537.5C534.13,-537.5 550.12,-538.5 614,-538.5"/>
|
||||
<path fill="none" stroke="#0066ff" stroke-width="2" d="M470,-539.5C534,-539.5 550,-540.5 614,-540.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-541.5C533.88,-541.5 549.87,-542.5 614,-542.5"/>
|
||||
</g>
|
||||
<!-- W1--X2 -->
|
||||
<g id="edge18" class="edge">
|
||||
<title>W1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-462.5C594.86,-465.31 485.48,-219.31 614,-216.5"/>
|
||||
<path fill="none" stroke="#8000ff" stroke-width="2" d="M470,-464.5C596.69,-464.5 487.31,-218.5 614,-218.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-466.5C598.52,-463.69 489.14,-217.69 614,-220.5"/>
|
||||
</g>
|
||||
<!-- W1--X2 -->
|
||||
<g id="edge20" class="edge">
|
||||
<title>W1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-487.5C562.43,-490.05 517.72,-334.05 614,-331.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-489.5C564.36,-489.5 519.64,-333.5 614,-333.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-491.5C566.28,-488.95 521.57,-332.95 614,-335.5"/>
|
||||
</g>
|
||||
<!-- W1--X2 -->
|
||||
<g id="edge22" class="edge">
|
||||
<title>W1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-412.5C658.48,-415.51 422.07,-12.51 614,-9.5"/>
|
||||
<path fill="none" stroke="#666600" stroke-width="2" d="M470,-414.5C660.2,-414.5 423.8,-11.5 614,-11.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-416.5C661.93,-413.49 425.52,-10.49 614,-13.5"/>
|
||||
</g>
|
||||
<!-- W1--X2 -->
|
||||
<g id="edge24" class="edge">
|
||||
<title>W1:e--X2:w</title>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-437.5C621.35,-440.42 459.1,-127.42 614,-124.5"/>
|
||||
<path fill="none" stroke="#ffffff" stroke-width="2" d="M470,-439.5C623.13,-439.5 460.87,-126.5 614,-126.5"/>
|
||||
<path fill="none" stroke="#000000" stroke-width="2" d="M470,-441.5C624.9,-438.58 462.65,-125.58 614,-128.5"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 33 KiB |
31
examples/ex09.yml
Normal file
@ -0,0 +1,31 @@
|
||||
# contributed by @kimmoli
|
||||
|
||||
connectors:
|
||||
X1:
|
||||
type: D-Sub
|
||||
subtype: male
|
||||
pincount: 25
|
||||
pinnumbers: [1,14,3,16,5,18,7,20,9,22,11,24,13]
|
||||
pinout: [ SENSE_P_1, SENSE_N_1, SENSE_P_2, SENSE_N_2, SENSE_P_3, SENSE_N_3, SENSE_P_4,SENSE_N_4, SENSE_P_5, SENSE_N_5, SENSE_P_6, SENSE_N_6, GND ]
|
||||
X2:
|
||||
type: F48
|
||||
subtype: female
|
||||
pincount: 48
|
||||
pinnumbers: [ z2,b2,d2,z4,b4,d4,z6,b6,d6,z8,b8,d8,z10,b10,d10,z12,b12,d12,z14,b14,d14,z16,b16,d16,z18,b18,d18,z20,b20,d20,z22,b22,d22,z24,b24,d24,z26,b26,d26,z28,b28,d28,z30,b30,d30,z32,b32,d32 ]
|
||||
|
||||
cables:
|
||||
W1:
|
||||
gauge: 0.25 mm2
|
||||
length: 0.2
|
||||
color_code: DIN
|
||||
wirecount: 12
|
||||
shield: true
|
||||
|
||||
connections:
|
||||
-
|
||||
- X1: [1,14,3,16,5,18,7,20,9,22,11,24]
|
||||
- W1: [2,1,4,3,6,5,8,7,10,9,12,11]
|
||||
- X2: [d4,z2,d10,z8,d16,z14,d20,z18,d26,z24,d32,z30]
|
||||
-
|
||||
- X1: 13
|
||||
- W1: s
|
||||
@ -39,3 +39,21 @@
|
||||
|
||||
[Source](ex07.yml) - [Bill of Materials](ex07.bom.tsv)
|
||||
|
||||
## Example 07
|
||||

|
||||
|
||||
[Source](ex07.yml) - [Bill of Materials](ex07.bom.tsv)
|
||||
|
||||
|
||||
## Example 08
|
||||

|
||||
|
||||
[Source](ex08.yml) - [Bill of Materials](ex08.bom.tsv)
|
||||
|
||||
|
||||
## Example 09
|
||||

|
||||
|
||||
[Source](ex09.yml) - [Bill of Materials](ex09.bom.tsv)
|
||||
|
||||
|
||||
|
||||
1
requirements.txt
Normal file
@ -0,0 +1 @@
|
||||
.
|
||||
45
setup.py
Normal file
@ -0,0 +1,45 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import os
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
project_name = 'wireviz'
|
||||
|
||||
# Utility function to read the README file.
|
||||
# Used for the long_description. It's nice, because now 1) we have a top level
|
||||
# README file and 2) it's easier to type in the README file than to put a raw
|
||||
# string in below ...
|
||||
def read(fname):
|
||||
return open(os.path.join(os.path.dirname(__file__), fname)).read()
|
||||
|
||||
setup(
|
||||
name=project_name,
|
||||
version='0.1',
|
||||
author='Daniel Rojas',
|
||||
#author_email='',
|
||||
description='Easily document cables and wiring harnesses',
|
||||
long_description=read(os.path.join(os.path.dirname(__file__), 'README.md')),
|
||||
long_description_content_type='text/markdown',
|
||||
install_requires=[
|
||||
'pyyaml',
|
||||
'graphviz',
|
||||
],
|
||||
license='GPLv3',
|
||||
keywords='cable connector hardware harness wiring wiring-diagram wiring-harness',
|
||||
url='https://github.com/formatc1702/WireViz',
|
||||
package_dir={'': 'src'},
|
||||
packages=find_packages('src'),
|
||||
entry_points={
|
||||
'console_scripts': ['wireviz=wireviz.wireviz:main'],
|
||||
},
|
||||
classifiers=[
|
||||
'Development Status :: 4 - Beta',
|
||||
'Environment :: Console',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Topic :: Utilities',
|
||||
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
|
||||
],
|
||||
|
||||
)
|
||||
@ -1,63 +0,0 @@
|
||||
# graphviz - create dot, save, render, view
|
||||
|
||||
"""Assemble DOT source code and render it with Graphviz.
|
||||
|
||||
>>> dot = Digraph(comment='The Round Table')
|
||||
|
||||
>>> dot.node('A', 'King Arthur')
|
||||
>>> dot.node('B', 'Sir Bedevere the Wise')
|
||||
>>> dot.node('L', 'Sir Lancelot the Brave')
|
||||
|
||||
>>> dot.edges(['AB', 'AL'])
|
||||
|
||||
>>> dot.edge('B', 'L', constraint='false')
|
||||
|
||||
>>> print(dot) #doctest: +NORMALIZE_WHITESPACE
|
||||
// The Round Table
|
||||
digraph {
|
||||
A [label="King Arthur"]
|
||||
B [label="Sir Bedevere the Wise"]
|
||||
L [label="Sir Lancelot the Brave"]
|
||||
A -> B
|
||||
A -> L
|
||||
B -> L [constraint=false]
|
||||
}
|
||||
"""
|
||||
|
||||
from .dot import Graph, Digraph
|
||||
from .files import Source
|
||||
from .lang import escape, nohtml
|
||||
from .backend import (render, pipe, version, view,
|
||||
ENGINES, FORMATS, RENDERERS, FORMATTERS,
|
||||
ExecutableNotFound, RequiredArgumentError)
|
||||
|
||||
__all__ = [
|
||||
'Graph', 'Digraph',
|
||||
'Source',
|
||||
'escape', 'nohtml',
|
||||
'render', 'pipe', 'version', 'view',
|
||||
'ENGINES', 'FORMATS', 'RENDERERS', 'FORMATTERS',
|
||||
'ExecutableNotFound', 'RequiredArgumentError',
|
||||
]
|
||||
|
||||
__title__ = 'graphviz'
|
||||
__version__ = '0.14.1.dev0'
|
||||
__author__ = 'Sebastian Bank <sebastian.bank@uni-leipzig.de>'
|
||||
__license__ = 'MIT, see LICENSE.txt'
|
||||
__copyright__ = 'Copyright (c) 2013-2020 Sebastian Bank'
|
||||
|
||||
#: Set of known layout commands used for rendering (``'dot'``, ``'neato'``, ...)
|
||||
ENGINES = ENGINES
|
||||
|
||||
#: Set of known output formats for rendering (``'pdf'``, ``'png'``, ...)
|
||||
FORMATS = FORMATS
|
||||
|
||||
#: Set of known output formatters for rendering (``'cairo'``, ``'gd'``, ...)
|
||||
FORMATTERS = FORMATTERS
|
||||
|
||||
#: Set of known output renderers for rendering (``'cairo'``, ``'gd'``, ...)
|
||||
RENDERERS = RENDERERS
|
||||
|
||||
ExecutableNotFound = ExecutableNotFound
|
||||
|
||||
RequiredArgumentError = RequiredArgumentError
|
||||
@ -1,69 +0,0 @@
|
||||
# _compat.py - Python 2/3 compatibility
|
||||
|
||||
import os
|
||||
import sys
|
||||
import operator
|
||||
import subprocess
|
||||
|
||||
PY2 = (sys.version_info.major == 2)
|
||||
|
||||
|
||||
if PY2:
|
||||
string_classes = (str, unicode) # needed individually for sublassing
|
||||
text_type = unicode
|
||||
|
||||
iteritems = operator.methodcaller('iteritems')
|
||||
|
||||
def makedirs(name, mode=0o777, exist_ok=False):
|
||||
try:
|
||||
os.makedirs(name, mode)
|
||||
except OSError:
|
||||
if not exist_ok or not os.path.isdir(name):
|
||||
raise
|
||||
|
||||
def stderr_write_bytes(data, flush=False):
|
||||
"""Write data str to sys.stderr (flush if requested)."""
|
||||
sys.stderr.write(data)
|
||||
if flush:
|
||||
sys.stderr.flush()
|
||||
|
||||
def Popen_stderr_devnull(*args, **kwargs): # noqa: N802
|
||||
with open(os.devnull, 'w') as f:
|
||||
return subprocess.Popen(*args, stderr=f, **kwargs)
|
||||
|
||||
class CalledProcessError(subprocess.CalledProcessError):
|
||||
|
||||
def __init__(self, returncode, cmd, output=None, stderr=None):
|
||||
super(CalledProcessError, self).__init__(returncode, cmd, output)
|
||||
self.stderr = stderr
|
||||
|
||||
@property # pragma: no cover
|
||||
def stdout(self):
|
||||
return self.output
|
||||
|
||||
@stdout.setter # pragma: no cover
|
||||
def stdout(self, value):
|
||||
self.output = value
|
||||
|
||||
|
||||
else:
|
||||
string_classes = (str,)
|
||||
text_type = str
|
||||
|
||||
def iteritems(d):
|
||||
return iter(d.items())
|
||||
|
||||
def makedirs(name, mode=0o777, exist_ok=False): # allow os.makedirs mocking
|
||||
return os.makedirs(name, mode, exist_ok=exist_ok)
|
||||
|
||||
def stderr_write_bytes(data, flush=False):
|
||||
"""Encode data str and write to sys.stderr (flush if requested)."""
|
||||
encoding = sys.stderr.encoding or sys.getdefaultencoding()
|
||||
sys.stderr.write(data.decode(encoding))
|
||||
if flush:
|
||||
sys.stderr.flush()
|
||||
|
||||
def Popen_stderr_devnull(*args, **kwargs): # noqa: N802
|
||||
return subprocess.Popen(*args, stderr=subprocess.DEVNULL, **kwargs)
|
||||
|
||||
CalledProcessError = subprocess.CalledProcessError
|
||||
@ -1,312 +0,0 @@
|
||||
# backend.py - execute rendering, open files in viewer
|
||||
|
||||
import os
|
||||
import re
|
||||
import errno
|
||||
import logging
|
||||
import platform
|
||||
import subprocess
|
||||
|
||||
from . import _compat
|
||||
|
||||
from . import tools
|
||||
|
||||
__all__ = [
|
||||
'render', 'pipe', 'version', 'view',
|
||||
'ENGINES', 'FORMATS', 'RENDERERS', 'FORMATTERS',
|
||||
'ExecutableNotFound', 'RequiredArgumentError',
|
||||
]
|
||||
|
||||
ENGINES = { # http://www.graphviz.org/pdf/dot.1.pdf
|
||||
'dot', 'neato', 'twopi', 'circo', 'fdp', 'sfdp', 'patchwork', 'osage',
|
||||
}
|
||||
|
||||
FORMATS = { # http://www.graphviz.org/doc/info/output.html
|
||||
'bmp',
|
||||
'canon', 'dot', 'gv', 'xdot', 'xdot1.2', 'xdot1.4',
|
||||
'cgimage',
|
||||
'cmap',
|
||||
'eps',
|
||||
'exr',
|
||||
'fig',
|
||||
'gd', 'gd2',
|
||||
'gif',
|
||||
'gtk',
|
||||
'ico',
|
||||
'imap', 'cmapx',
|
||||
'imap_np', 'cmapx_np',
|
||||
'ismap',
|
||||
'jp2',
|
||||
'jpg', 'jpeg', 'jpe',
|
||||
'json', 'json0', 'dot_json', 'xdot_json', # Graphviz 2.40
|
||||
'pct', 'pict',
|
||||
'pdf',
|
||||
'pic',
|
||||
'plain', 'plain-ext',
|
||||
'png',
|
||||
'pov',
|
||||
'ps',
|
||||
'ps2',
|
||||
'psd',
|
||||
'sgi',
|
||||
'svg', 'svgz',
|
||||
'tga',
|
||||
'tif', 'tiff',
|
||||
'tk',
|
||||
'vml', 'vmlz',
|
||||
'vrml',
|
||||
'wbmp',
|
||||
'webp',
|
||||
'xlib',
|
||||
'x11',
|
||||
}
|
||||
|
||||
RENDERERS = { # $ dot -T:
|
||||
'cairo',
|
||||
'dot',
|
||||
'fig',
|
||||
'gd',
|
||||
'gdiplus',
|
||||
'map',
|
||||
'pic',
|
||||
'pov',
|
||||
'ps',
|
||||
'svg',
|
||||
'tk',
|
||||
'vml',
|
||||
'vrml',
|
||||
'xdot',
|
||||
}
|
||||
|
||||
FORMATTERS = {'cairo', 'core', 'gd', 'gdiplus', 'gdwbmp', 'xlib'}
|
||||
|
||||
PLATFORM = platform.system().lower()
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ExecutableNotFound(RuntimeError):
|
||||
"""Exception raised if the Graphviz executable is not found."""
|
||||
|
||||
_msg = ('failed to execute %r, '
|
||||
'make sure the Graphviz executables are on your systems\' PATH')
|
||||
|
||||
def __init__(self, args):
|
||||
super(ExecutableNotFound, self).__init__(self._msg % args)
|
||||
|
||||
|
||||
class RequiredArgumentError(Exception):
|
||||
"""Exception raised if a required argument is missing."""
|
||||
|
||||
|
||||
class CalledProcessError(_compat.CalledProcessError):
|
||||
|
||||
def __str__(self):
|
||||
s = super(CalledProcessError, self).__str__()
|
||||
return '%s [stderr: %r]' % (s, self.stderr)
|
||||
|
||||
|
||||
def command(engine, format_, filepath=None, renderer=None, formatter=None):
|
||||
"""Return args list for ``subprocess.Popen`` and name of the rendered file."""
|
||||
if formatter is not None and renderer is None:
|
||||
raise RequiredArgumentError('formatter given without renderer')
|
||||
|
||||
if engine not in ENGINES:
|
||||
raise ValueError('unknown engine: %r' % engine)
|
||||
if format_ not in FORMATS:
|
||||
raise ValueError('unknown format: %r' % format_)
|
||||
if renderer is not None and renderer not in RENDERERS:
|
||||
raise ValueError('unknown renderer: %r' % renderer)
|
||||
if formatter is not None and formatter not in FORMATTERS:
|
||||
raise ValueError('unknown formatter: %r' % formatter)
|
||||
|
||||
output_format = [f for f in (format_, renderer, formatter) if f is not None]
|
||||
cmd = [engine, '-T%s' % ':'.join(output_format)]
|
||||
|
||||
if filepath is None:
|
||||
rendered = None
|
||||
else:
|
||||
cmd.extend(['-O', filepath])
|
||||
suffix = '.'.join(reversed(output_format))
|
||||
rendered = '%s.%s' % (filepath, suffix)
|
||||
|
||||
return cmd, rendered
|
||||
|
||||
|
||||
if PLATFORM == 'windows': # pragma: no cover
|
||||
def get_startupinfo():
|
||||
"""Return subprocess.STARTUPINFO instance hiding the console window."""
|
||||
startupinfo = subprocess.STARTUPINFO()
|
||||
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||
startupinfo.wShowWindow = subprocess.SW_HIDE
|
||||
return startupinfo
|
||||
else:
|
||||
def get_startupinfo():
|
||||
"""Return None for startupinfo argument of ``subprocess.Popen``."""
|
||||
return None
|
||||
|
||||
|
||||
def run(cmd, input=None, capture_output=False, check=False, encoding=None,
|
||||
quiet=False, **kwargs):
|
||||
"""Run the command described by cmd and return its (stdout, stderr) tuple."""
|
||||
log.debug('run %r', cmd)
|
||||
|
||||
if input is not None:
|
||||
kwargs['stdin'] = subprocess.PIPE
|
||||
if encoding is not None:
|
||||
input = input.encode(encoding)
|
||||
|
||||
if capture_output:
|
||||
kwargs['stdout'] = kwargs['stderr'] = subprocess.PIPE
|
||||
|
||||
try:
|
||||
proc = subprocess.Popen(cmd, startupinfo=get_startupinfo(), **kwargs)
|
||||
except OSError as e:
|
||||
if e.errno == errno.ENOENT:
|
||||
raise ExecutableNotFound(cmd)
|
||||
else:
|
||||
raise
|
||||
|
||||
out, err = proc.communicate(input)
|
||||
|
||||
if not quiet and err:
|
||||
_compat.stderr_write_bytes(err, flush=True)
|
||||
|
||||
if encoding is not None:
|
||||
if out is not None:
|
||||
out = out.decode(encoding)
|
||||
if err is not None:
|
||||
err = err.decode(encoding)
|
||||
|
||||
if check and proc.returncode:
|
||||
raise CalledProcessError(proc.returncode, cmd,
|
||||
output=out, stderr=err)
|
||||
|
||||
return out, err
|
||||
|
||||
|
||||
def render(engine, format, filepath, renderer=None, formatter=None, quiet=False):
|
||||
"""Render file with Graphviz ``engine`` into ``format``, return result filename.
|
||||
|
||||
Args:
|
||||
engine: The layout commmand used for rendering (``'dot'``, ``'neato'``, ...).
|
||||
format: The output format used for rendering (``'pdf'``, ``'png'``, ...).
|
||||
filepath: Path to the DOT source file to render.
|
||||
renderer: The output renderer used for rendering (``'cairo'``, ``'gd'``, ...).
|
||||
formatter: The output formatter used for rendering (``'cairo'``, ``'gd'``, ...).
|
||||
quiet (bool): Suppress ``stderr`` output from the layout subprocess.
|
||||
Returns:
|
||||
The (possibly relative) path of the rendered file.
|
||||
Raises:
|
||||
ValueError: If ``engine``, ``format``, ``renderer``, or ``formatter`` are not known.
|
||||
graphviz.RequiredArgumentError: If ``formatter`` is given but ``renderer`` is None.
|
||||
graphviz.ExecutableNotFound: If the Graphviz executable is not found.
|
||||
subprocess.CalledProcessError: If the exit status is non-zero.
|
||||
|
||||
The layout command is started from the directory of ``filepath``, so that
|
||||
references to external files (e.g. ``[image=...]``) can be given as paths
|
||||
relative to the DOT source file.
|
||||
"""
|
||||
dirname, filename = os.path.split(filepath)
|
||||
del filepath
|
||||
|
||||
cmd, rendered = command(engine, format, filename, renderer, formatter)
|
||||
if dirname:
|
||||
cwd = dirname
|
||||
rendered = os.path.join(dirname, rendered)
|
||||
else:
|
||||
cwd = None
|
||||
|
||||
run(cmd, capture_output=True, cwd=cwd, check=True, quiet=quiet)
|
||||
return rendered
|
||||
|
||||
|
||||
def pipe(engine, format, data, renderer=None, formatter=None, quiet=False):
|
||||
"""Return ``data`` piped through Graphviz ``engine`` into ``format``.
|
||||
|
||||
Args:
|
||||
engine: The layout commmand used for rendering (``'dot'``, ``'neato'``, ...).
|
||||
format: The output format used for rendering (``'pdf'``, ``'png'``, ...).
|
||||
data: The binary (encoded) DOT source string to render.
|
||||
renderer: The output renderer used for rendering (``'cairo'``, ``'gd'``, ...).
|
||||
formatter: The output formatter used for rendering (``'cairo'``, ``'gd'``, ...).
|
||||
quiet (bool): Suppress ``stderr`` output from the layout subprocess.
|
||||
Returns:
|
||||
Binary (encoded) stdout of the layout command.
|
||||
Raises:
|
||||
ValueError: If ``engine``, ``format``, ``renderer``, or ``formatter`` are not known.
|
||||
graphviz.RequiredArgumentError: If ``formatter`` is given but ``renderer`` is None.
|
||||
graphviz.ExecutableNotFound: If the Graphviz executable is not found.
|
||||
subprocess.CalledProcessError: If the exit status is non-zero.
|
||||
"""
|
||||
cmd, _ = command(engine, format, None, renderer, formatter)
|
||||
out, _ = run(cmd, input=data, capture_output=True, check=True, quiet=quiet)
|
||||
return out
|
||||
|
||||
|
||||
def version():
|
||||
"""Return the version number tuple from the ``stderr`` output of ``dot -V``.
|
||||
|
||||
Returns:
|
||||
Two, three, or four ``int`` version ``tuple``.
|
||||
Raises:
|
||||
graphviz.ExecutableNotFound: If the Graphviz executable is not found.
|
||||
subprocess.CalledProcessError: If the exit status is non-zero.
|
||||
RuntimmeError: If the output cannot be parsed into a version number.
|
||||
"""
|
||||
cmd = ['dot', '-V']
|
||||
out, _ = run(cmd, check=True, encoding='ascii',
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
|
||||
ma = re.search(r'graphviz version (\d+\.\d+(?:\.\d+){,2}) ', out)
|
||||
if ma is None:
|
||||
raise RuntimeError('cannot parse %r output: %r' % (cmd, out))
|
||||
|
||||
return tuple(int(d) for d in ma.group(1).split('.'))
|
||||
|
||||
|
||||
def view(filepath, quiet=False):
|
||||
"""Open filepath with its default viewing application (platform-specific).
|
||||
|
||||
Args:
|
||||
filepath: Path to the file to open in viewer.
|
||||
quiet (bool): Suppress ``stderr`` output from the viewer process
|
||||
(ineffective on Windows).
|
||||
Raises:
|
||||
RuntimeError: If the current platform is not supported.
|
||||
"""
|
||||
try:
|
||||
view_func = getattr(view, PLATFORM)
|
||||
except AttributeError:
|
||||
raise RuntimeError('platform %r not supported' % PLATFORM)
|
||||
view_func(filepath, quiet)
|
||||
|
||||
|
||||
@tools.attach(view, 'darwin')
|
||||
def view_darwin(filepath, quiet):
|
||||
"""Open filepath with its default application (mac)."""
|
||||
cmd = ['open', filepath]
|
||||
log.debug('view: %r', cmd)
|
||||
popen_func = _compat.Popen_stderr_devnull if quiet else subprocess.Popen
|
||||
popen_func(cmd)
|
||||
|
||||
|
||||
@tools.attach(view, 'linux')
|
||||
@tools.attach(view, 'freebsd')
|
||||
def view_unixoid(filepath, quiet):
|
||||
"""Open filepath in the user's preferred application (linux, freebsd)."""
|
||||
cmd = ['xdg-open', filepath]
|
||||
log.debug('view: %r', cmd)
|
||||
popen_func = _compat.Popen_stderr_devnull if quiet else subprocess.Popen
|
||||
popen_func(cmd)
|
||||
|
||||
|
||||
@tools.attach(view, 'windows')
|
||||
def view_windows(filepath, quiet):
|
||||
"""Start filepath with its associated application (windows)."""
|
||||
# TODO: implement quiet=True
|
||||
filepath = os.path.normpath(filepath)
|
||||
log.debug('view: %r', filepath)
|
||||
os.startfile(filepath)
|
||||
@ -1,287 +0,0 @@
|
||||
# dot.py - create dot code
|
||||
|
||||
r"""Assemble DOT source code objects.
|
||||
|
||||
>>> dot = Graph(comment=u'M\xf8nti Pyth\xf8n ik den H\xf8lie Grailen')
|
||||
|
||||
>>> dot.node(u'M\xf8\xf8se')
|
||||
>>> dot.node('trained_by', u'trained by')
|
||||
>>> dot.node('tutte', u'TUTTE HERMSGERVORDENBROTBORDA')
|
||||
|
||||
>>> dot.edge(u'M\xf8\xf8se', 'trained_by')
|
||||
>>> dot.edge('trained_by', 'tutte')
|
||||
|
||||
>>> dot.node_attr['shape'] = 'rectangle'
|
||||
|
||||
>>> print(dot.source.replace(u'\xf8', '0')) #doctest: +NORMALIZE_WHITESPACE
|
||||
// M0nti Pyth0n ik den H0lie Grailen
|
||||
graph {
|
||||
node [shape=rectangle]
|
||||
"M00se"
|
||||
trained_by [label="trained by"]
|
||||
tutte [label="TUTTE HERMSGERVORDENBROTBORDA"]
|
||||
"M00se" -- trained_by
|
||||
trained_by -- tutte
|
||||
}
|
||||
|
||||
>>> dot.view('test-output/m00se.gv') # doctest: +SKIP
|
||||
'test-output/m00se.gv.pdf'
|
||||
"""
|
||||
|
||||
from . import lang
|
||||
from . import files
|
||||
|
||||
__all__ = ['Graph', 'Digraph']
|
||||
|
||||
|
||||
class Dot(files.File):
|
||||
"""Assemble, save, and render DOT source code, open result in viewer."""
|
||||
|
||||
_comment = '// %s'
|
||||
_subgraph = 'subgraph %s{'
|
||||
_subgraph_plain = '%s{'
|
||||
_node = _attr = '\t%s%s'
|
||||
_attr_plain = _attr % ('%s', '')
|
||||
_tail = '}'
|
||||
|
||||
_quote = staticmethod(lang.quote)
|
||||
_quote_edge = staticmethod(lang.quote_edge)
|
||||
|
||||
_a_list = staticmethod(lang.a_list)
|
||||
_attr_list = staticmethod(lang.attr_list)
|
||||
|
||||
def __init__(self, name=None, comment=None,
|
||||
filename=None, directory=None,
|
||||
format=None, engine=None, encoding=files.ENCODING,
|
||||
graph_attr=None, node_attr=None, edge_attr=None, body=None,
|
||||
strict=False):
|
||||
self.name = name
|
||||
self.comment = comment
|
||||
|
||||
super(Dot, self).__init__(filename, directory, format, engine, encoding)
|
||||
|
||||
self.graph_attr = dict(graph_attr) if graph_attr is not None else {}
|
||||
self.node_attr = dict(node_attr) if node_attr is not None else {}
|
||||
self.edge_attr = dict(edge_attr) if edge_attr is not None else {}
|
||||
|
||||
self.body = list(body) if body is not None else []
|
||||
|
||||
self.strict = strict
|
||||
|
||||
def _kwargs(self):
|
||||
result = super(Dot, self)._kwargs()
|
||||
result.update(name=self.name,
|
||||
comment=self.comment,
|
||||
graph_attr=dict(self.graph_attr),
|
||||
node_attr=dict(self.node_attr),
|
||||
edge_attr=dict(self.edge_attr),
|
||||
body=list(self.body),
|
||||
strict=self.strict)
|
||||
return result
|
||||
|
||||
def clear(self, keep_attrs=False):
|
||||
"""Reset content to an empty body, clear graph/node/egde_attr mappings.
|
||||
|
||||
Args:
|
||||
keep_attrs (bool): preserve graph/node/egde_attr mappings
|
||||
"""
|
||||
if not keep_attrs:
|
||||
for a in (self.graph_attr, self.node_attr, self.edge_attr):
|
||||
a.clear()
|
||||
del self.body[:]
|
||||
|
||||
def __iter__(self, subgraph=False):
|
||||
"""Yield the DOT source code line by line (as graph or subgraph)."""
|
||||
if self.comment:
|
||||
yield self._comment % self.comment
|
||||
|
||||
if subgraph:
|
||||
if self.strict:
|
||||
raise ValueError('subgraphs cannot be strict')
|
||||
head = self._subgraph if self.name else self._subgraph_plain
|
||||
else:
|
||||
head = self._head_strict if self.strict else self._head
|
||||
yield head % (self._quote(self.name) + ' ' if self.name else '')
|
||||
|
||||
for kw in ('graph', 'node', 'edge'):
|
||||
attrs = getattr(self, '%s_attr' % kw)
|
||||
if attrs:
|
||||
yield self._attr % (kw, self._attr_list(None, attrs))
|
||||
|
||||
for line in self.body:
|
||||
yield line
|
||||
|
||||
yield self._tail
|
||||
|
||||
def __str__(self):
|
||||
"""The DOT source code as string."""
|
||||
return '\n'.join(self)
|
||||
|
||||
source = property(__str__, doc=__str__.__doc__)
|
||||
|
||||
def node(self, name, label=None, _attributes=None, **attrs):
|
||||
"""Create a node.
|
||||
|
||||
Args:
|
||||
name: Unique identifier for the node inside the source.
|
||||
label: Caption to be displayed (defaults to the node ``name``).
|
||||
attrs: Any additional node attributes (must be strings).
|
||||
"""
|
||||
name = self._quote(name)
|
||||
attr_list = self._attr_list(label, attrs, _attributes)
|
||||
line = self._node % (name, attr_list)
|
||||
self.body.append(line)
|
||||
|
||||
def edge(self, tail_name, head_name, label=None, _attributes=None, **attrs):
|
||||
"""Create an edge between two nodes.
|
||||
|
||||
Args:
|
||||
tail_name: Start node identifier.
|
||||
head_name: End node identifier.
|
||||
label: Caption to be displayed near the edge.
|
||||
attrs: Any additional edge attributes (must be strings).
|
||||
"""
|
||||
tail_name = self._quote_edge(tail_name)
|
||||
head_name = self._quote_edge(head_name)
|
||||
attr_list = self._attr_list(label, attrs, _attributes)
|
||||
line = self._edge % (tail_name, head_name, attr_list)
|
||||
self.body.append(line)
|
||||
|
||||
def edges(self, tail_head_iter):
|
||||
"""Create a bunch of edges.
|
||||
|
||||
Args:
|
||||
tail_head_iter: Iterable of ``(tail_name, head_name)`` pairs.
|
||||
"""
|
||||
edge = self._edge_plain
|
||||
quote = self._quote_edge
|
||||
lines = (edge % (quote(t), quote(h)) for t, h in tail_head_iter)
|
||||
self.body.extend(lines)
|
||||
|
||||
def attr(self, kw=None, _attributes=None, **attrs):
|
||||
"""Add a general or graph/node/edge attribute statement.
|
||||
|
||||
Args:
|
||||
kw: Attributes target (``None`` or ``'graph'``, ``'node'``, ``'edge'``).
|
||||
attrs: Attributes to be set (must be strings, may be empty).
|
||||
|
||||
See the :ref:`usage examples in the User Guide <attributes>`.
|
||||
"""
|
||||
if kw is not None and kw.lower() not in ('graph', 'node', 'edge'):
|
||||
raise ValueError('attr statement must target graph, node, or edge: '
|
||||
'%r' % kw)
|
||||
if attrs or _attributes:
|
||||
if kw is None:
|
||||
a_list = self._a_list(None, attrs, _attributes)
|
||||
line = self._attr_plain % a_list
|
||||
else:
|
||||
attr_list = self._attr_list(None, attrs, _attributes)
|
||||
line = self._attr % (kw, attr_list)
|
||||
self.body.append(line)
|
||||
|
||||
def subgraph(self, graph=None, name=None, comment=None,
|
||||
graph_attr=None, node_attr=None, edge_attr=None, body=None):
|
||||
"""Add the current content of the given sole ``graph`` argument as subgraph \
|
||||
or return a context manager returning a new graph instance created \
|
||||
with the given (``name``, ``comment``, etc.) arguments whose content is \
|
||||
added as subgraph when leaving the context manager's ``with``-block.
|
||||
|
||||
Args:
|
||||
graph: An instance of the same kind (:class:`.Graph`, :class:`.Digraph`)
|
||||
as the current graph (sole argument in non-with-block use).
|
||||
name: Subgraph name (``with``-block use).
|
||||
comment: Subgraph comment (``with``-block use).
|
||||
graph_attr: Subgraph-level attribute-value mapping (``with``-block use).
|
||||
node_attr: Node-level attribute-value mapping (``with``-block use).
|
||||
edge_attr: Edge-level attribute-value mapping (``with``-block use).
|
||||
body: Verbatim lines to add to the subgraph ``body`` (``with``-block use).
|
||||
|
||||
See the :ref:`usage examples in the User Guide <subgraphs>`.
|
||||
|
||||
.. note::
|
||||
If the ``name`` of the subgraph begins with ``'cluster'`` (all lowercase)
|
||||
the layout engine will treat it as a special cluster subgraph.
|
||||
"""
|
||||
if graph is None:
|
||||
return SubgraphContext(self, {'name': name,
|
||||
'comment': comment,
|
||||
'graph_attr': graph_attr,
|
||||
'node_attr': node_attr,
|
||||
'edge_attr': edge_attr,
|
||||
'body': body})
|
||||
|
||||
args = [name, comment, graph_attr, node_attr, edge_attr, body]
|
||||
if not all(a is None for a in args):
|
||||
raise ValueError('graph must be sole argument of subgraph()')
|
||||
|
||||
if graph.directed != self.directed:
|
||||
raise ValueError('%r cannot add subgraph of different kind:'
|
||||
' %r' % (self, graph))
|
||||
|
||||
lines = ['\t' + line for line in graph.__iter__(subgraph=True)]
|
||||
self.body.extend(lines)
|
||||
|
||||
|
||||
class SubgraphContext(object):
|
||||
"""Return a blank instance of the parent and add as subgraph on exit."""
|
||||
|
||||
def __init__(self, parent, kwargs):
|
||||
self.parent = parent
|
||||
self.graph = parent.__class__(**kwargs)
|
||||
|
||||
def __enter__(self):
|
||||
return self.graph
|
||||
|
||||
def __exit__(self, type_, value, traceback):
|
||||
if type_ is None:
|
||||
self.parent.subgraph(self.graph)
|
||||
|
||||
|
||||
class Graph(Dot):
|
||||
"""Graph source code in the DOT language.
|
||||
|
||||
Args:
|
||||
name: Graph name used in the source code.
|
||||
comment: Comment added to the first line of the source.
|
||||
filename: Filename for saving the source (defaults to ``name`` + ``'.gv'``).
|
||||
directory: (Sub)directory for source saving and rendering.
|
||||
format: Rendering output format (``'pdf'``, ``'png'``, ...).
|
||||
engine: Layout command used (``'dot'``, ``'neato'``, ...).
|
||||
encoding: Encoding for saving the source.
|
||||
graph_attr: Mapping of ``(attribute, value)`` pairs for the graph.
|
||||
node_attr: Mapping of ``(attribute, value)`` pairs set for all nodes.
|
||||
edge_attr: Mapping of ``(attribute, value)`` pairs set for all edges.
|
||||
body: Iterable of verbatim lines to add to the graph ``body``.
|
||||
strict (bool): Rendering should merge multi-edges.
|
||||
|
||||
Note:
|
||||
All parameters are optional and can be changed under their
|
||||
corresponding attribute name after instance creation.
|
||||
"""
|
||||
|
||||
_head = 'graph %s{'
|
||||
_head_strict = 'strict %s' % _head
|
||||
_edge = '\t%s -- %s%s'
|
||||
_edge_plain = _edge % ('%s', '%s', '')
|
||||
|
||||
@property
|
||||
def directed(self):
|
||||
"""``False``"""
|
||||
return False
|
||||
|
||||
|
||||
class Digraph(Dot):
|
||||
"""Directed graph source code in the DOT language."""
|
||||
|
||||
if Graph.__doc__ is not None:
|
||||
__doc__ += Graph.__doc__.partition('.')[2]
|
||||
|
||||
_head = 'digraph %s{'
|
||||
_head_strict = 'strict %s' % _head
|
||||
_edge = '\t%s -> %s%s'
|
||||
_edge_plain = _edge % ('%s', '%s', '')
|
||||
|
||||
@property
|
||||
def directed(self):
|
||||
"""``True``"""
|
||||
return True
|
||||
@ -1,311 +0,0 @@
|
||||
# files.py - save, render, view
|
||||
|
||||
"""Save DOT code objects, render with Graphviz dot, and open in viewer."""
|
||||
|
||||
import os
|
||||
import io
|
||||
import codecs
|
||||
import locale
|
||||
import logging
|
||||
|
||||
from ._compat import text_type
|
||||
|
||||
from . import backend
|
||||
from . import tools
|
||||
|
||||
__all__ = ['File', 'Source']
|
||||
|
||||
ENCODING = 'utf-8'
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Base(object):
|
||||
|
||||
_format = 'pdf'
|
||||
_engine = 'dot'
|
||||
_encoding = ENCODING
|
||||
|
||||
@property
|
||||
def format(self):
|
||||
"""The output format used for rendering (``'pdf'``, ``'png'``, ...)."""
|
||||
return self._format
|
||||
|
||||
@format.setter
|
||||
def format(self, format):
|
||||
format = format.lower()
|
||||
if format not in backend.FORMATS:
|
||||
raise ValueError('unknown format: %r' % format)
|
||||
self._format = format
|
||||
|
||||
@property
|
||||
def engine(self):
|
||||
"""The layout commmand used for rendering (``'dot'``, ``'neato'``, ...)."""
|
||||
return self._engine
|
||||
|
||||
@engine.setter
|
||||
def engine(self, engine):
|
||||
engine = engine.lower()
|
||||
if engine not in backend.ENGINES:
|
||||
raise ValueError('unknown engine: %r' % engine)
|
||||
self._engine = engine
|
||||
|
||||
@property
|
||||
def encoding(self):
|
||||
"""The encoding for the saved source file."""
|
||||
return self._encoding
|
||||
|
||||
@encoding.setter
|
||||
def encoding(self, encoding):
|
||||
if encoding is None:
|
||||
encoding = locale.getpreferredencoding()
|
||||
codecs.lookup(encoding) # raise early
|
||||
self._encoding = encoding
|
||||
|
||||
def copy(self):
|
||||
"""Return a copied instance of the object.
|
||||
|
||||
Returns:
|
||||
An independent copy of the current object.
|
||||
"""
|
||||
kwargs = self._kwargs()
|
||||
return self.__class__(**kwargs)
|
||||
|
||||
def _kwargs(self):
|
||||
ns = self.__dict__
|
||||
return {a[1:]: ns[a] for a in ('_format', '_engine', '_encoding')
|
||||
if a in ns}
|
||||
|
||||
|
||||
class File(Base):
|
||||
|
||||
directory = ''
|
||||
|
||||
_default_extension = 'gv'
|
||||
|
||||
def __init__(self, filename=None, directory=None,
|
||||
format=None, engine=None, encoding=ENCODING):
|
||||
if filename is None:
|
||||
name = getattr(self, 'name', None) or self.__class__.__name__
|
||||
filename = '%s.%s' % (name, self._default_extension)
|
||||
self.filename = filename
|
||||
|
||||
if directory is not None:
|
||||
self.directory = directory
|
||||
|
||||
if format is not None:
|
||||
self.format = format
|
||||
|
||||
if engine is not None:
|
||||
self.engine = engine
|
||||
|
||||
self.encoding = encoding
|
||||
|
||||
def _kwargs(self):
|
||||
result = super(File, self)._kwargs()
|
||||
result['filename'] = self.filename
|
||||
if 'directory' in self.__dict__:
|
||||
result['directory'] = self.directory
|
||||
return result
|
||||
|
||||
def _repr_svg_(self):
|
||||
return self.pipe(format='svg').decode(self._encoding)
|
||||
|
||||
def pipe(self, format=None, renderer=None, formatter=None, quiet=False):
|
||||
"""Return the source piped through the Graphviz layout command.
|
||||
|
||||
Args:
|
||||
format: The output format used for rendering (``'pdf'``, ``'png'``, etc.).
|
||||
renderer: The output renderer used for rendering (``'cairo'``, ``'gd'``, ...).
|
||||
formatter: The output formatter used for rendering (``'cairo'``, ``'gd'``, ...).
|
||||
quiet (bool): Suppress ``stderr`` output from the layout subprocess.
|
||||
Returns:
|
||||
Binary (encoded) stdout of the layout command.
|
||||
Raises:
|
||||
ValueError: If ``format``, ``renderer``, or ``formatter`` are not known.
|
||||
graphviz.RequiredArgumentError: If ``formatter`` is given but ``renderer`` is None.
|
||||
graphviz.ExecutableNotFound: If the Graphviz executable is not found.
|
||||
subprocess.CalledProcessError: If the exit status is non-zero.
|
||||
"""
|
||||
if format is None:
|
||||
format = self._format
|
||||
|
||||
data = text_type(self.source).encode(self._encoding)
|
||||
|
||||
out = backend.pipe(self._engine, format, data,
|
||||
renderer=renderer, formatter=formatter,
|
||||
quiet=quiet)
|
||||
|
||||
return out
|
||||
|
||||
@property
|
||||
def filepath(self):
|
||||
return os.path.join(self.directory, self.filename)
|
||||
|
||||
def save(self, filename=None, directory=None):
|
||||
"""Save the DOT source to file. Ensure the file ends with a newline.
|
||||
|
||||
Args:
|
||||
filename: Filename for saving the source (defaults to ``name`` + ``'.gv'``)
|
||||
directory: (Sub)directory for source saving and rendering.
|
||||
Returns:
|
||||
The (possibly relative) path of the saved source file.
|
||||
"""
|
||||
if filename is not None:
|
||||
self.filename = filename
|
||||
if directory is not None:
|
||||
self.directory = directory
|
||||
|
||||
filepath = self.filepath
|
||||
tools.mkdirs(filepath)
|
||||
|
||||
data = text_type(self.source)
|
||||
|
||||
log.debug('write %d bytes to %r', len(data), filepath)
|
||||
with io.open(filepath, 'w', encoding=self.encoding) as fd:
|
||||
fd.write(data)
|
||||
if not data.endswith(u'\n'):
|
||||
fd.write(u'\n')
|
||||
|
||||
return filepath
|
||||
|
||||
def render(self, filename=None, directory=None, view=False, cleanup=False,
|
||||
format=None, renderer=None, formatter=None,
|
||||
quiet=False, quiet_view=False):
|
||||
"""Save the source to file and render with the Graphviz engine.
|
||||
|
||||
Args:
|
||||
filename: Filename for saving the source (defaults to ``name`` + ``'.gv'``)
|
||||
directory: (Sub)directory for source saving and rendering.
|
||||
view (bool): Open the rendered result with the default application.
|
||||
cleanup (bool): Delete the source file after rendering.
|
||||
format: The output format used for rendering (``'pdf'``, ``'png'``, etc.).
|
||||
renderer: The output renderer used for rendering (``'cairo'``, ``'gd'``, ...).
|
||||
formatter: The output formatter used for rendering (``'cairo'``, ``'gd'``, ...).
|
||||
quiet (bool): Suppress ``stderr`` output from the layout subprocess.
|
||||
quiet_view (bool): Suppress ``stderr`` output from the viewer process
|
||||
(implies ``view=True``, ineffective on Windows).
|
||||
Returns:
|
||||
The (possibly relative) path of the rendered file.
|
||||
Raises:
|
||||
ValueError: If ``format``, ``renderer``, or ``formatter`` are not known.
|
||||
graphviz.RequiredArgumentError: If ``formatter`` is given but ``renderer`` is None.
|
||||
graphviz.ExecutableNotFound: If the Graphviz executable is not found.
|
||||
subprocess.CalledProcessError: If the exit status is non-zero.
|
||||
RuntimeError: If viewer opening is requested but not supported.
|
||||
|
||||
The layout command is started from the directory of ``filepath``, so that
|
||||
references to external files (e.g. ``[image=...]``) can be given as paths
|
||||
relative to the DOT source file.
|
||||
"""
|
||||
filepath = self.save(filename, directory)
|
||||
|
||||
if format is None:
|
||||
format = self._format
|
||||
|
||||
rendered = backend.render(self._engine, format, filepath,
|
||||
renderer=renderer, formatter=formatter,
|
||||
quiet=quiet)
|
||||
|
||||
if cleanup:
|
||||
log.debug('delete %r', filepath)
|
||||
os.remove(filepath)
|
||||
|
||||
if quiet_view or view:
|
||||
self._view(rendered, self._format, quiet_view)
|
||||
|
||||
return rendered
|
||||
|
||||
def view(self, filename=None, directory=None, cleanup=False,
|
||||
quiet=False, quiet_view=False):
|
||||
"""Save the source to file, open the rendered result in a viewer.
|
||||
|
||||
Args:
|
||||
filename: Filename for saving the source (defaults to ``name`` + ``'.gv'``)
|
||||
directory: (Sub)directory for source saving and rendering.
|
||||
cleanup (bool): Delete the source file after rendering.
|
||||
quiet (bool): Suppress ``stderr`` output from the layout subprocess.
|
||||
quiet_view (bool): Suppress ``stderr`` output from the viewer process
|
||||
(ineffective on Windows).
|
||||
Returns:
|
||||
The (possibly relative) path of the rendered file.
|
||||
Raises:
|
||||
graphviz.ExecutableNotFound: If the Graphviz executable is not found.
|
||||
subprocess.CalledProcessError: If the exit status is non-zero.
|
||||
RuntimeError: If opening the viewer is not supported.
|
||||
|
||||
Short-cut method for calling :meth:`.render` with ``view=True``.
|
||||
"""
|
||||
return self.render(filename=filename, directory=directory,
|
||||
view=True, cleanup=cleanup,
|
||||
quiet=quiet, quiet_view=quiet_view)
|
||||
|
||||
def _view(self, filepath, format, quiet):
|
||||
"""Start the right viewer based on file format and platform."""
|
||||
methodnames = [
|
||||
'_view_%s_%s' % (format, backend.PLATFORM),
|
||||
'_view_%s' % backend.PLATFORM,
|
||||
]
|
||||
for name in methodnames:
|
||||
view_method = getattr(self, name, None)
|
||||
if view_method is not None:
|
||||
break
|
||||
else:
|
||||
raise RuntimeError('%r has no built-in viewer support for %r'
|
||||
' on %r platform' % (self.__class__, format,
|
||||
backend.PLATFORM))
|
||||
view_method(filepath, quiet)
|
||||
|
||||
_view_darwin = staticmethod(backend.view.darwin)
|
||||
_view_freebsd = staticmethod(backend.view.freebsd)
|
||||
_view_linux = staticmethod(backend.view.linux)
|
||||
_view_windows = staticmethod(backend.view.windows)
|
||||
|
||||
|
||||
class Source(File):
|
||||
"""Verbatim DOT source code string to be rendered by Graphviz.
|
||||
|
||||
Args:
|
||||
source: The verbatim DOT source code string.
|
||||
filename: Filename for saving the source (defaults to ``'Source.gv'``).
|
||||
directory: (Sub)directory for source saving and rendering.
|
||||
format: Rendering output format (``'pdf'``, ``'png'``, ...).
|
||||
engine: Layout command used (``'dot'``, ``'neato'``, ...).
|
||||
encoding: Encoding for saving the source.
|
||||
|
||||
Note:
|
||||
All parameters except ``source`` are optional. All of them can be changed
|
||||
under their corresponding attribute name after instance creation.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def from_file(cls, filename, directory=None,
|
||||
format=None, engine=None, encoding=ENCODING):
|
||||
"""Return an instance with the source string read from the given file.
|
||||
|
||||
Args:
|
||||
filename: Filename for loading/saving the source.
|
||||
directory: (Sub)directory for source loading/saving and rendering.
|
||||
format: Rendering output format (``'pdf'``, ``'png'``, ...).
|
||||
engine: Layout command used (``'dot'``, ``'neato'``, ...).
|
||||
encoding: Encoding for loading/saving the source.
|
||||
"""
|
||||
filepath = os.path.join(directory or '', filename)
|
||||
if encoding is None:
|
||||
encoding = locale.getpreferredencoding()
|
||||
log.debug('read %r with encoding %r', filepath, encoding)
|
||||
with io.open(filepath, encoding=encoding) as fd:
|
||||
source = fd.read()
|
||||
return cls(source, filename, directory, format, engine, encoding)
|
||||
|
||||
def __init__(self, source, filename=None, directory=None,
|
||||
format=None, engine=None, encoding=ENCODING):
|
||||
super(Source, self).__init__(filename, directory,
|
||||
format, engine, encoding)
|
||||
self.source = source #: The verbatim DOT source code string.
|
||||
|
||||
def _kwargs(self):
|
||||
result = super(Source, self)._kwargs()
|
||||
result['source'] = self.source
|
||||
return result
|
||||
@ -1,195 +0,0 @@
|
||||
# lang.py - dot language creation helpers
|
||||
|
||||
"""Quote strings to be valid DOT identifiers, assemble attribute lists."""
|
||||
|
||||
import re
|
||||
import collections
|
||||
import functools
|
||||
|
||||
from . import _compat
|
||||
|
||||
from . import tools
|
||||
|
||||
__all__ = ['quote', 'quote_edge', 'a_list', 'attr_list', 'escape', 'nohtml']
|
||||
|
||||
# https://www.graphviz.org/doc/info/lang.html
|
||||
# https://www.graphviz.org/doc/info/attrs.html#k:escString
|
||||
|
||||
HTML_STRING = re.compile(r'<.*>$', re.DOTALL)
|
||||
|
||||
ID = re.compile(r'([a-zA-Z_][a-zA-Z0-9_]*|-?(\.[0-9]+|[0-9]+(\.[0-9]*)?))$')
|
||||
|
||||
KEYWORDS = {'node', 'edge', 'graph', 'digraph', 'subgraph', 'strict'}
|
||||
|
||||
COMPASS = {'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', 'c', '_'} # TODO
|
||||
|
||||
QUOTE_OPTIONAL_BACKSLASHES = re.compile(r'(?P<bs>(?:\\\\)*)'
|
||||
r'\\?(?P<quote>")')
|
||||
|
||||
ESCAPE_UNESCAPED_QUOTES = functools.partial(QUOTE_OPTIONAL_BACKSLASHES.sub,
|
||||
r'\g<bs>\\\g<quote>')
|
||||
|
||||
|
||||
def quote(identifier,
|
||||
is_html_string=HTML_STRING.match,
|
||||
is_valid_id=ID.match, dot_keywords=KEYWORDS,
|
||||
escape_unescaped_quotes=ESCAPE_UNESCAPED_QUOTES):
|
||||
r"""Return DOT identifier from string, quote if needed.
|
||||
|
||||
>>> quote('')
|
||||
'""'
|
||||
|
||||
>>> quote('spam')
|
||||
'spam'
|
||||
|
||||
>>> quote('spam spam')
|
||||
'"spam spam"'
|
||||
|
||||
>>> quote('-4.2')
|
||||
'-4.2'
|
||||
|
||||
>>> quote('.42')
|
||||
'.42'
|
||||
|
||||
>>> quote('<<b>spam</b>>')
|
||||
'<<b>spam</b>>'
|
||||
|
||||
>>> quote(nohtml('<>'))
|
||||
'"<>"'
|
||||
|
||||
>>> print(quote('"'))
|
||||
"\""
|
||||
|
||||
>>> print(quote('\\"'))
|
||||
"\""
|
||||
|
||||
>>> print(quote('\\\\"'))
|
||||
"\\\""
|
||||
|
||||
>>> print(quote('\\\\\\"'))
|
||||
"\\\""
|
||||
"""
|
||||
if is_html_string(identifier) and not isinstance(identifier, NoHtml):
|
||||
pass
|
||||
elif not is_valid_id(identifier) or identifier.lower() in dot_keywords:
|
||||
return '"%s"' % escape_unescaped_quotes(identifier)
|
||||
return identifier
|
||||
|
||||
|
||||
def quote_edge(identifier):
|
||||
"""Return DOT edge statement node_id from string, quote if needed.
|
||||
|
||||
>>> quote_edge('spam')
|
||||
'spam'
|
||||
|
||||
>>> quote_edge('spam spam:eggs eggs')
|
||||
'"spam spam":"eggs eggs"'
|
||||
|
||||
>>> quote_edge('spam:eggs:s')
|
||||
'spam:eggs:s'
|
||||
"""
|
||||
node, _, rest = identifier.partition(':')
|
||||
parts = [quote(node)]
|
||||
if rest:
|
||||
port, _, compass = rest.partition(':')
|
||||
parts.append(quote(port))
|
||||
if compass:
|
||||
parts.append(compass)
|
||||
return ':'.join(parts)
|
||||
|
||||
|
||||
def a_list(label=None, kwargs=None, attributes=None):
|
||||
"""Return assembled DOT a_list string.
|
||||
|
||||
>>> a_list('spam', {'spam': None, 'ham': 'ham ham', 'eggs': ''})
|
||||
'label=spam eggs="" ham="ham ham"'
|
||||
"""
|
||||
result = ['label=%s' % quote(label)] if label is not None else []
|
||||
if kwargs:
|
||||
items = ['%s=%s' % (quote(k), quote(v))
|
||||
for k, v in tools.mapping_items(kwargs) if v is not None]
|
||||
result.extend(items)
|
||||
if attributes:
|
||||
if hasattr(attributes, 'items'):
|
||||
attributes = tools.mapping_items(attributes)
|
||||
items = ['%s=%s' % (quote(k), quote(v))
|
||||
for k, v in attributes if v is not None]
|
||||
result.extend(items)
|
||||
return ' '.join(result)
|
||||
|
||||
|
||||
def attr_list(label=None, kwargs=None, attributes=None):
|
||||
"""Return assembled DOT attribute list string.
|
||||
|
||||
Sorts ``kwargs`` and ``attributes`` if they are plain dicts (to avoid
|
||||
unpredictable order from hash randomization in Python 3 versions).
|
||||
|
||||
>>> attr_list()
|
||||
''
|
||||
|
||||
>>> attr_list('spam spam', kwargs={'eggs': 'eggs', 'ham': 'ham ham'})
|
||||
' [label="spam spam" eggs=eggs ham="ham ham"]'
|
||||
|
||||
>>> attr_list(kwargs={'spam': None, 'eggs': ''})
|
||||
' [eggs=""]'
|
||||
"""
|
||||
content = a_list(label, kwargs, attributes)
|
||||
if not content:
|
||||
return ''
|
||||
return ' [%s]' % content
|
||||
|
||||
|
||||
def escape(s):
|
||||
r"""Return ``s`` as literal disabling special meaning of backslashes and ``'<...>'``.
|
||||
|
||||
see also https://www.graphviz.org/doc/info/attrs.html#k:escString
|
||||
|
||||
Args:
|
||||
s: String in which backslashes and ``'<...>'`` should be treated as literal.
|
||||
Raises:
|
||||
TypeError: If ``s`` is not a ``str`` on Python 3, or a ``str``/``unicode`` on Python 2.
|
||||
|
||||
>>> print(escape(r'\l'))
|
||||
\\l
|
||||
"""
|
||||
return nohtml(s.replace('\\', '\\\\'))
|
||||
|
||||
|
||||
class NoHtml(object):
|
||||
"""Mixin for string subclasses disabling fall-through of ``'<...>'``."""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
_doc = "%s subclass that does not treat ``'<...>'`` as DOT HTML string."
|
||||
|
||||
@classmethod
|
||||
def _subcls(cls, other):
|
||||
name = '%s_%s' % (cls.__name__, other.__name__)
|
||||
bases = (other, cls)
|
||||
ns = {'__doc__': cls._doc % other.__name__}
|
||||
return type(name, bases, ns)
|
||||
|
||||
|
||||
NOHTML = collections.OrderedDict((c, NoHtml._subcls(c)) for c in _compat.string_classes)
|
||||
|
||||
|
||||
def nohtml(s):
|
||||
"""Return copy of ``s`` that will not treat ``'<...>'`` as DOT HTML string in quoting.
|
||||
|
||||
Args:
|
||||
s: String in which leading ``'<'`` and trailing ``'>'`` should be treated as literal.
|
||||
Raises:
|
||||
TypeError: If ``s`` is not a ``str`` on Python 3, or a ``str``/``unicode`` on Python 2.
|
||||
|
||||
>>> quote('<>-*-<>')
|
||||
'<>-*-<>'
|
||||
|
||||
>>> quote(nohtml('<>-*-<>'))
|
||||
'"<>-*-<>"'
|
||||
"""
|
||||
try:
|
||||
subcls = NOHTML[type(s)]
|
||||
except KeyError:
|
||||
raise TypeError('%r does not have one of the required types:'
|
||||
' %r' % (s, list(NOHTML)))
|
||||
return subcls(s)
|
||||
@ -1,47 +0,0 @@
|
||||
# tools.py - generic helpers
|
||||
|
||||
import os
|
||||
|
||||
from . import _compat
|
||||
|
||||
__all__ = ['attach', 'mkdirs', 'mapping_items']
|
||||
|
||||
|
||||
def attach(object, name):
|
||||
"""Return a decorator doing ``setattr(object, name)`` with its argument.
|
||||
|
||||
>>> spam = type('Spam', (object,), {})()
|
||||
>>> @attach(spam, 'eggs')
|
||||
... def func():
|
||||
... pass
|
||||
>>> spam.eggs # doctest: +ELLIPSIS
|
||||
<function func at 0x...>
|
||||
"""
|
||||
def decorator(func):
|
||||
setattr(object, name, func)
|
||||
return func
|
||||
return decorator
|
||||
|
||||
|
||||
def mkdirs(filename, mode=0o777):
|
||||
"""Recursively create directories up to the path of ``filename`` as needed."""
|
||||
dirname = os.path.dirname(filename)
|
||||
if not dirname:
|
||||
return
|
||||
_compat.makedirs(dirname, mode=mode, exist_ok=True)
|
||||
|
||||
|
||||
def mapping_items(mapping):
|
||||
"""Return an iterator over the ``mapping`` items, sort if it's a plain dict.
|
||||
|
||||
>>> list(mapping_items({'spam': 0, 'ham': 1, 'eggs': 2}))
|
||||
[('eggs', 2), ('ham', 1), ('spam', 0)]
|
||||
|
||||
>>> from collections import OrderedDict
|
||||
>>> list(mapping_items(OrderedDict(enumerate(['spam', 'ham', 'eggs']))))
|
||||
[(0, 'spam'), (1, 'ham'), (2, 'eggs')]
|
||||
"""
|
||||
result = _compat.iteritems(mapping)
|
||||
if type(mapping) is dict:
|
||||
result = iter(sorted(result))
|
||||
return result
|
||||
1
src/.gitignore → src/wireviz/.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
__pycache__/
|
||||
_test/
|
||||
wv-env/
|
||||
141
src/wireviz/DataClasses.py
Normal file
@ -0,0 +1,141 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from typing import Optional, List, Any
|
||||
from dataclasses import dataclass, field
|
||||
from wireviz.wv_helper import int2tuple
|
||||
from wireviz import wv_colors
|
||||
|
||||
|
||||
@dataclass
|
||||
class Connector:
|
||||
name: str
|
||||
category: Optional[str] = None
|
||||
type: Optional[str] = None
|
||||
subtype: Optional[str] = None
|
||||
pincount: Optional[int] = None
|
||||
notes: Optional[str] = None
|
||||
pinout: List[Any] = field(default_factory=list)
|
||||
pinnumbers: List[Any] = field(default_factory=list)
|
||||
color: Optional[str] = None
|
||||
show_name: bool = True
|
||||
show_pincount: bool = True
|
||||
hide_disconnected_pins: bool = False
|
||||
|
||||
def __post_init__(self):
|
||||
self.ports_left = False
|
||||
self.ports_right = False
|
||||
self.loops = []
|
||||
self.visible_pins = {}
|
||||
|
||||
if self.pincount is None:
|
||||
if self.pinout:
|
||||
self.pincount = len(self.pinout)
|
||||
elif self.pinnumbers:
|
||||
self.pincount = len(self.pinnumbers)
|
||||
elif self.category == 'ferrule':
|
||||
self.pincount = 1
|
||||
else:
|
||||
raise Exception('You need to specify at least one, pincount, pinout or pinnumbers')
|
||||
|
||||
if self.pinout and self.pinnumbers:
|
||||
if len(self.pinout) != len(self.pinnumbers):
|
||||
raise Exception('Given pinout and pinnumbers size mismatch')
|
||||
|
||||
# create default lists for pinnumbers (sequential) and pinouts (blank) if not specified
|
||||
if not self.pinnumbers:
|
||||
self.pinnumbers = list(range(1, self.pincount + 1))
|
||||
if not self.pinout:
|
||||
self.pinout = [''] * self.pincount
|
||||
|
||||
def loop(self, from_pin, to_pin):
|
||||
self.loops.append((from_pin, to_pin))
|
||||
if self.hide_disconnected_pins:
|
||||
self.visible_pins[from_pin] = True
|
||||
self.visible_pins[to_pin] = True
|
||||
|
||||
def activate_pin(self, pin):
|
||||
self.visible_pins[pin] = True
|
||||
|
||||
|
||||
@dataclass
|
||||
class Cable:
|
||||
name: str
|
||||
category: Optional[str] = None
|
||||
type: Optional[str] = None
|
||||
gauge: Optional[float] = None
|
||||
gauge_unit: Optional[str] = None
|
||||
show_equiv: bool = False
|
||||
length: float = 0
|
||||
wirecount: Optional[int] = None
|
||||
shield: bool = False
|
||||
notes: Optional[str] = None
|
||||
colors: List[Any] = field(default_factory=list)
|
||||
color_code: Optional[str] = None
|
||||
show_name: bool = True
|
||||
show_wirecount: bool = True
|
||||
|
||||
def __post_init__(self):
|
||||
|
||||
if isinstance(self.gauge, str): # gauge and unit specified
|
||||
try:
|
||||
g, u = self.gauge.split(' ')
|
||||
except Exception:
|
||||
raise Exception('Gauge must be a number, or number and unit separated by a space')
|
||||
self.gauge = g
|
||||
|
||||
if u.upper() == 'AWG':
|
||||
self.gauge_unit = u.upper()
|
||||
else:
|
||||
self.gauge_unit = u.replace('mm2', 'mm\u00B2')
|
||||
|
||||
elif self.gauge is not None: # gauge specified, assume mm2
|
||||
if self.gauge_unit is None:
|
||||
self.gauge_unit = 'mm\u00B2'
|
||||
else:
|
||||
pass # gauge not specified
|
||||
|
||||
self.connections = []
|
||||
|
||||
if self.wirecount: # number of wires explicitly defined
|
||||
if self.colors: # use custom color palette (partly or looped if needed)
|
||||
pass
|
||||
elif self.color_code: # use standard color palette (partly or looped if needed)
|
||||
if self.color_code not in wv_colors.COLOR_CODES:
|
||||
raise Exception('Unknown color code')
|
||||
self.colors = wv_colors.COLOR_CODES[self.color_code]
|
||||
else: # no colors defined, add dummy colors
|
||||
self.colors = [''] * self.wirecount
|
||||
|
||||
# make color code loop around if more wires than colors
|
||||
if self.wirecount > len(self.colors):
|
||||
m = self.wirecount // len(self.colors) + 1
|
||||
self.colors = self.colors * int(m)
|
||||
# cut off excess after looping
|
||||
self.colors = self.colors[:self.wirecount]
|
||||
else: # wirecount implicit in length of color list
|
||||
if not self.colors:
|
||||
raise Exception('Unknown number of wires. Must specify wirecount or colors (implicit length)')
|
||||
self.wirecount = len(self.colors)
|
||||
|
||||
# for BOM generation
|
||||
self.wirecount_and_shield = (self.wirecount, self.shield)
|
||||
|
||||
def connect(self, from_name, from_pin, via_pin, to_name, to_pin):
|
||||
from_pin = int2tuple(from_pin)
|
||||
via_pin = int2tuple(via_pin)
|
||||
to_pin = int2tuple(to_pin)
|
||||
if len(from_pin) != len(to_pin):
|
||||
raise Exception('from_pin must have the same number of elements as to_pin')
|
||||
for i, _ in enumerate(from_pin):
|
||||
# self.connections.append((from_name, from_pin[i], via_pin[i], to_name, to_pin[i]))
|
||||
self.connections.append(Connection(from_name, from_pin[i], via_pin[i], to_name, to_pin[i]))
|
||||
|
||||
|
||||
@dataclass
|
||||
class Connection:
|
||||
from_name: Any
|
||||
from_port: Any
|
||||
via_port: Any
|
||||
to_name: Any
|
||||
to_port: Any
|
||||
331
src/wireviz/Harness.py
Normal file
@ -0,0 +1,331 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from wireviz.DataClasses import Connector, Cable
|
||||
from graphviz import Graph
|
||||
from wireviz import wv_colors
|
||||
from wireviz.wv_helper import awg_equiv, mm2_equiv, tuplelist2tsv, nested, flatten2d
|
||||
from collections import Counter
|
||||
from typing import List
|
||||
|
||||
|
||||
class Harness:
|
||||
|
||||
def __init__(self):
|
||||
self.color_mode = 'SHORT'
|
||||
self.connectors = {}
|
||||
self.cables = {}
|
||||
|
||||
def add_connector(self, name, *args, **kwargs):
|
||||
self.connectors[name] = Connector(name, *args, **kwargs)
|
||||
|
||||
def add_cable(self, name, *args, **kwargs):
|
||||
self.cables[name] = Cable(name, *args, **kwargs)
|
||||
|
||||
def loop(self, connector_name, from_pin, to_pin):
|
||||
self.connectors[connector_name].loop(from_pin, to_pin)
|
||||
|
||||
def connect(self, from_name, from_pin, via_name, via_pin, to_name, to_pin):
|
||||
self.cables[via_name].connect(from_name, from_pin, via_pin, to_name, to_pin)
|
||||
if from_name in self.connectors:
|
||||
self.connectors[from_name].activate_pin(from_pin)
|
||||
if to_name in self.connectors:
|
||||
self.connectors[to_name].activate_pin(to_pin)
|
||||
|
||||
def create_graph(self):
|
||||
dot = Graph()
|
||||
dot.body.append('// Graph generated by WireViz')
|
||||
dot.body.append('// https://github.com/formatc1702/WireViz')
|
||||
font = 'arial'
|
||||
dot.attr('graph', rankdir='LR',
|
||||
ranksep='2',
|
||||
bgcolor='white',
|
||||
nodesep='0.33',
|
||||
fontname=font)
|
||||
dot.attr('node', shape='record',
|
||||
style='filled',
|
||||
fillcolor='white',
|
||||
fontname=font)
|
||||
dot.attr('edge', style='bold',
|
||||
fontname=font)
|
||||
|
||||
# prepare ports on connectors depending on which side they will connect
|
||||
for _, cable in self.cables.items():
|
||||
for connection in cable.connections:
|
||||
if connection.from_port is not None: # connect to left
|
||||
self.connectors[connection.from_name].ports_right = True
|
||||
if connection.to_port is not None: # connect to right
|
||||
self.connectors[connection.to_name].ports_left = True
|
||||
|
||||
for key, connector in self.connectors.items():
|
||||
if connector.category == 'ferrule':
|
||||
subtype = f', {connector.subtype}' if connector.subtype else ''
|
||||
color = wv_colors.translate_color(connector.color, self.color_mode) if connector.color else ''
|
||||
infostring = f'{connector.type}{subtype} {color}'
|
||||
infostring_l = infostring if connector.ports_right else ''
|
||||
infostring_r = infostring if connector.ports_left else ''
|
||||
|
||||
# INFO: Leaving this one as a string.format form because f-strings do not work well with triple quotes
|
||||
colorbar = f'<TD BGCOLOR="{wv_colors.translate_color(connector.color, "HEX")}" BORDER="1" SIDES="LR" WIDTH="4"></TD>' if connector.color else ''
|
||||
dot.node(key, shape='none',
|
||||
style='filled',
|
||||
margin='0',
|
||||
orientation='0' if connector.ports_left else '180',
|
||||
label='''<
|
||||
|
||||
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" CELLPADDING="2"><TR>
|
||||
<TD PORT="p1l"> {infostring_l} </TD>
|
||||
{colorbar}
|
||||
<TD PORT="p1r"> {infostring_r} </TD>
|
||||
</TR></TABLE>
|
||||
|
||||
|
||||
>'''.format(infostring_l=infostring_l, infostring_r=infostring_r, colorbar=colorbar))
|
||||
|
||||
else: # not a ferrule
|
||||
attributes = [connector.type,
|
||||
connector.subtype,
|
||||
f'{connector.pincount}-pin' if connector.show_pincount else'']
|
||||
pinouts = [[], [], []]
|
||||
for pinnumber, pinname in zip(connector.pinnumbers, connector.pinout):
|
||||
if connector.hide_disconnected_pins and not connector.visible_pins.get(pinnumber, False):
|
||||
continue
|
||||
pinouts[1].append(pinname)
|
||||
if connector.ports_left:
|
||||
pinouts[0].append(f'<p{pinnumber}l>{pinnumber}')
|
||||
if connector.ports_right:
|
||||
pinouts[2].append(f'<p{pinnumber}r>{pinnumber}')
|
||||
label = [connector.name if connector.show_name else '', attributes, pinouts, connector.notes]
|
||||
dot.node(key, label=nested(label))
|
||||
|
||||
if len(connector.loops) > 0:
|
||||
dot.attr('edge', color='#000000:#ffffff:#000000')
|
||||
if connector.ports_left:
|
||||
loop_side = 'l'
|
||||
loop_dir = 'w'
|
||||
elif connector.ports_right:
|
||||
loop_side = 'r'
|
||||
loop_dir = 'e'
|
||||
else:
|
||||
raise Exception('No side for loops')
|
||||
for loop in connector.loops:
|
||||
dot.edge(f'{connector.name}:p{loop[0]}{loop_side}:{loop_dir}',
|
||||
f'{connector.name}:p{loop[1]}{loop_side}:{loop_dir}')
|
||||
|
||||
for _, cable in self.cables.items():
|
||||
|
||||
awg_fmt = ''
|
||||
if cable.show_equiv:
|
||||
# Only convert units we actually know about, i.e. currently
|
||||
# mm2 and awg --- other units _are_ technically allowed,
|
||||
# and passed through as-is.
|
||||
if cable.gauge_unit =='mm\u00B2':
|
||||
awg_fmt = f' ({awg_equiv(cable.gauge)} AWG)'
|
||||
elif cable.gauge_unit.upper() == 'AWG':
|
||||
awg_fmt = f' ({mm2_equiv(cable.gauge)} mm\u00B2)'
|
||||
|
||||
attributes = [f'{len(cable.colors)}x' if cable.show_wirecount else '',
|
||||
f'{cable.gauge} {cable.gauge_unit}{awg_fmt}' if cable.gauge else '',
|
||||
'+ S' if cable.shield else '',
|
||||
f'{cable.length} m' if cable.length > 0 else '']
|
||||
attributes = list(filter(None, attributes))
|
||||
|
||||
html = '<table border="0" cellspacing="0" cellpadding="0"><tr><td>' # main table
|
||||
|
||||
html = f'{html}<table border="0" cellspacing="0" cellpadding="3" cellborder="1">' # name+attributes table
|
||||
if cable.show_name:
|
||||
html = f'{html}<tr><td colspan="{len(attributes)}">{cable.name}</td></tr>'
|
||||
html = f'{html}<tr>' # attribute row
|
||||
for attrib in attributes:
|
||||
html = f'{html}<td>{attrib}</td>'
|
||||
html = f'{html}</tr>' # attribute row
|
||||
html = f'{html}</table></td></tr>' # name+attributes table
|
||||
|
||||
html = f'{html}<tr><td> </td></tr>' # spacer between attributes and wires
|
||||
|
||||
html = f'{html}<tr><td><table border="0" cellspacing="0" cellborder="0">' # conductor table
|
||||
|
||||
for i, connection in enumerate(cable.colors, 1):
|
||||
p = []
|
||||
p.append(f'<!-- {i}_in -->')
|
||||
p.append(wv_colors.translate_color(connection, self.color_mode))
|
||||
p.append(f'<!-- {i}_out -->')
|
||||
html = f'{html}<tr>'
|
||||
for bla in p:
|
||||
html = f'{html}<td>{bla}</td>'
|
||||
html = f'{html}</tr>'
|
||||
bgcolor = wv_colors.translate_color(connection, 'hex')
|
||||
bgcolor = bgcolor if bgcolor != '' else '#ffffff'
|
||||
html = f'{html}<tr><td colspan="{len(p)}" cellpadding="0" height="6" bgcolor="{bgcolor}" border="2" sides="tb" port="w{i}"></td></tr>'
|
||||
|
||||
if cable.shield:
|
||||
p = ['<!-- s_in -->', 'Shield', '<!-- s_out -->']
|
||||
html = f'{html}<tr><td> </td></tr>' # spacer
|
||||
html = f'{html}<tr>'
|
||||
for bla in p:
|
||||
html = html + f'<td>{bla}</td>'
|
||||
html = f'{html}</tr>'
|
||||
html = f'{html}<tr><td colspan="{len(p)}" cellpadding="0" height="6" border="2" sides="b" port="ws"></td></tr>'
|
||||
|
||||
html = f'{html}<tr><td> </td></tr>' # spacer at the end
|
||||
|
||||
html = f'{html}</table>' # conductor table
|
||||
|
||||
html = f'{html}</td></tr>' # main table
|
||||
if cable.notes:
|
||||
html = f'{html}<tr><td cellpadding="3">{cable.notes}</td></tr>' # notes table
|
||||
html = f'{html}<tr><td> </td></tr>' # spacer at the end
|
||||
|
||||
html = f'{html}</table>' # main table
|
||||
|
||||
# connections
|
||||
for connection in cable.connections:
|
||||
if isinstance(connection.via_port, int): # check if it's an actual wire and not a shield
|
||||
search_color = cable.colors[connection.via_port - 1]
|
||||
if search_color in wv_colors.color_hex:
|
||||
dot.attr('edge', color=f'#000000:{wv_colors.color_hex[search_color]}:#000000')
|
||||
else: # color name not found
|
||||
dot.attr('edge', color='#000000:#ffffff:#000000')
|
||||
else: # it's a shield connection
|
||||
dot.attr('edge', color='#000000')
|
||||
|
||||
if connection.from_port is not None: # connect to left
|
||||
from_ferrule = self.connectors[connection.from_name].category == 'ferrule'
|
||||
port = f':p{connection.from_port}r' if not from_ferrule else ''
|
||||
code_left_1 = f'{connection.from_name}{port}:e'
|
||||
code_left_2 = f'{cable.name}:w{connection.via_port}:w'
|
||||
dot.edge(code_left_1, code_left_2)
|
||||
from_string = f'{connection.from_name}:{connection.from_port}' if not from_ferrule else ''
|
||||
html = html.replace(f'<!-- {connection.via_port}_in -->', from_string)
|
||||
if connection.to_port is not None: # connect to right
|
||||
to_ferrule = self.connectors[connection.to_name].category == 'ferrule'
|
||||
code_right_1 = f'{cable.name}:w{connection.via_port}:e'
|
||||
to_port = f':p{connection.to_port}l' if not to_ferrule else ''
|
||||
code_right_2 = f'{connection.to_name}{to_port}:w'
|
||||
dot.edge(code_right_1, code_right_2)
|
||||
to_string = f'{connection.to_name}:{connection.to_port}' if not to_ferrule else ''
|
||||
html = html.replace(f'<!-- {connection.via_port}_out -->', to_string)
|
||||
|
||||
dot.node(cable.name, label=f'<{html}>', shape='box',
|
||||
style='filled,dashed' if cable.category == 'bundle' else '', margin='0', fillcolor='white')
|
||||
|
||||
return dot
|
||||
|
||||
def output(self, filename, directory='_output', view=False, cleanup=True, fmt='pdf', gen_bom=False):
|
||||
# graphical output
|
||||
graph = self.create_graph()
|
||||
for f in fmt:
|
||||
graph.format = f
|
||||
graph.render(filename=filename, directory=directory, view=view, cleanup=cleanup)
|
||||
graph.save(filename=f'{filename}.gv', directory=directory)
|
||||
# bom output
|
||||
bom_list = self.bom_list()
|
||||
with open(f'{filename}.bom.tsv', 'w') as file:
|
||||
file.write(tuplelist2tsv(bom_list))
|
||||
# HTML output
|
||||
with open(f'{filename}.html', 'w') as file:
|
||||
file.write('<html><body style="font-family:Arial">')
|
||||
|
||||
file.write('<h1>Diagram</h1>')
|
||||
with open(f'{filename}.svg') as svg:
|
||||
for svgdata in svg:
|
||||
file.write(svgdata)
|
||||
|
||||
file.write('<h1>Bill of Materials</h1>')
|
||||
listy = flatten2d(bom_list)
|
||||
file.write('<table style="border:1px solid #000000; font-size: 14pt; border-spacing: 0px">')
|
||||
file.write('<tr>')
|
||||
for item in listy[0]:
|
||||
file.write(f'<th align="left" style="border:1px solid #000000; padding: 8px">{item}</th>')
|
||||
file.write('</tr>')
|
||||
for row in listy[1:]:
|
||||
file.write('<tr>')
|
||||
for i, item in enumerate(row):
|
||||
align = 'align="right"' if listy[0][i] == 'Qty' else ''
|
||||
file.write(f'<td {align} style="border:1px solid #000000; padding: 4px">{item}</td>')
|
||||
file.write('</tr>')
|
||||
file.write('</table>')
|
||||
|
||||
file.write('</body></html>')
|
||||
|
||||
def bom(self):
|
||||
bom = []
|
||||
bom_connectors = []
|
||||
bom_cables = []
|
||||
# connectors
|
||||
types = Counter([(v.type, v.subtype, v.pincount) for v in self.connectors.values()])
|
||||
for maintype in types:
|
||||
items = {k: v for k, v in self.connectors.items() if (v.type, v.subtype, v.pincount) == maintype}
|
||||
shared = next(iter(items.values()))
|
||||
designators = list(items.keys())
|
||||
designators.sort()
|
||||
conn_type = f', {shared.type}' if shared.type else ''
|
||||
conn_subtype = f', {shared.subtype}' if shared.subtype else ''
|
||||
conn_pincount = f', {shared.pincount} pins' if shared.category != 'ferrule' else ''
|
||||
conn_color = f', {shared.color}' if shared.color else ''
|
||||
name = f'Connector{conn_type}{conn_subtype}{conn_pincount}{conn_color}'
|
||||
item = {'item': name, 'qty': len(designators), 'unit': '',
|
||||
'designators': designators if shared.category != 'ferrule' else ''}
|
||||
bom_connectors.append(item)
|
||||
bom_connectors = sorted(bom_connectors, key=lambda k: k['item']) # https://stackoverflow.com/a/73050
|
||||
bom.extend(bom_connectors)
|
||||
# cables
|
||||
types = Counter([(v.category, v.gauge, v.gauge_unit, v.wirecount, v.shield) for v in self.cables.values()])
|
||||
for maintype in types:
|
||||
items = {k: v for k, v in self.cables.items() if (
|
||||
v.category, v.gauge, v.gauge_unit, v.wirecount, v.shield) == maintype}
|
||||
shared = next(iter(items.values()))
|
||||
if shared.category != 'bundle':
|
||||
designators = list(items.keys())
|
||||
designators.sort()
|
||||
total_length = sum(i.length for i in items.values())
|
||||
gauge_name = f' x {shared.gauge} {shared.gauge_unit}'if shared.gauge else ' wires'
|
||||
shield_name = ' shielded' if shared.shield else ''
|
||||
name = f'Cable, {shared.wirecount}{gauge_name}{shield_name}'
|
||||
item = {'item': name, 'qty': round(total_length, 3), 'unit': 'm', 'designators': designators}
|
||||
bom_cables.append(item)
|
||||
# bundles (ignores wirecount)
|
||||
wirelist = []
|
||||
# list all cables again, since bundles are represented as wires internally, with the category='bundle' set
|
||||
types = Counter([(v.category, v.gauge, v.gauge_unit, v.length) for v in self.cables.values()])
|
||||
for maintype in types:
|
||||
items = {k: v for k, v in self.cables.items() if (v.category, v.gauge, v.gauge_unit, v.length) == maintype}
|
||||
shared = next(iter(items.values()))
|
||||
# filter out cables that are not bundles
|
||||
if shared.category == 'bundle':
|
||||
for bundle in items.values():
|
||||
# add each wire from each bundle to the wirelist
|
||||
for color in bundle.colors:
|
||||
wirelist.append({'gauge': shared.gauge, 'gauge_unit': shared.gauge_unit,
|
||||
'length': shared.length, 'color': color, 'designator': bundle.name})
|
||||
# join similar wires from all the bundles to a single BOM item
|
||||
types = Counter([(v['gauge'], v['gauge_unit'], v['color']) for v in wirelist])
|
||||
for maintype in types:
|
||||
items = [v for v in wirelist if (v['gauge'], v['gauge_unit'], v['color']) == maintype]
|
||||
shared = items[0]
|
||||
designators = [i['designator'] for i in items]
|
||||
# remove duplicates
|
||||
designators = list(dict.fromkeys(designators))
|
||||
designators.sort()
|
||||
total_length = sum(i['length'] for i in items)
|
||||
gauge_name = f', {shared["gauge"]} {shared["gauge_unit"]}' if shared['gauge'] else ''
|
||||
gauge_color = f', {shared["color"]}' if shared['color'] != '' else ''
|
||||
name = f'Wire{gauge_name}{gauge_color}'
|
||||
item = {'item': name, 'qty': round(total_length, 3), 'unit': 'm', 'designators': designators}
|
||||
bom_cables.append(item)
|
||||
bom_cables = sorted(bom_cables, key=lambda k: k['item']) # https://stackoverflow.com/a/73050
|
||||
bom.extend(bom_cables)
|
||||
return bom
|
||||
|
||||
def bom_list(self):
|
||||
bom = self.bom()
|
||||
keys = ['item', 'qty', 'unit', 'designators']
|
||||
bom_list = []
|
||||
bom_list.append([k.capitalize() for k in keys]) # create header row with keys
|
||||
for item in bom:
|
||||
item_list = [item.get(key, '') for key in keys] # fill missing values with blanks
|
||||
for i, subitem in enumerate(item_list):
|
||||
if isinstance(subitem, List): # convert any lists into comma separated strings
|
||||
item_list[i] = ', '.join(subitem)
|
||||
bom_list.append(item_list)
|
||||
return bom_list
|
||||
0
src/wireviz/__init__.py
Normal file
57
src/wireviz/build_examples.py
Executable file
@ -0,0 +1,57 @@
|
||||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
|
||||
|
||||
from wireviz import wireviz
|
||||
|
||||
demos = 2 # 2
|
||||
examples = 9 # 9
|
||||
tutorials = 7 # 7
|
||||
|
||||
if demos:
|
||||
for i in range(1,demos+1):
|
||||
fn = '../../examples/demo{:02d}.yml'.format(i)
|
||||
print(fn)
|
||||
wireviz.parse_file(fn, generate_bom=True)
|
||||
|
||||
if examples:
|
||||
with open(os.path.abspath('../../examples/readme.md'), 'w') as file:
|
||||
file.write('# Example gallery\n')
|
||||
for i in range(1,examples+1):
|
||||
fn = '../../examples/ex{:02d}.yml'.format(i)
|
||||
print(fn)
|
||||
wireviz.parse_file(fn, generate_bom=True)
|
||||
|
||||
file.write('## Example {:02d}\n'.format(i))
|
||||
file.write('\n\n'.format(i))
|
||||
file.write('[Source](ex{:02d}.yml) - [Bill of Materials](ex{:02d}.bom.tsv)\n\n\n'.format(i,i))
|
||||
|
||||
if tutorials:
|
||||
with open(os.path.abspath('../../tutorial/readme.md'), 'w') as file:
|
||||
file.write('# WireViz Tutorial\n')
|
||||
for i in range(1,tutorials+1):
|
||||
fn = '../../tutorial/tutorial{:02d}.yml'.format(i)
|
||||
print(fn)
|
||||
wireviz.parse_file(fn, generate_bom=True)
|
||||
|
||||
with open(os.path.abspath('../../tutorial/tutorial{:02d}.md'.format(i)), 'r') as info:
|
||||
for line in info:
|
||||
file.write(line.replace('## ', '## {} - '.format(i)))
|
||||
file.write('\n[Source](tutorial{:02d}.yml):\n\n'.format(i))
|
||||
|
||||
with open(os.path.abspath('../../tutorial/tutorial{:02d}.yml'.format(i)), 'r') as src:
|
||||
file.write('```yaml\n')
|
||||
for line in src:
|
||||
file.write(line)
|
||||
file.write('```\n')
|
||||
file.write('\n')
|
||||
|
||||
file.write('\nOutput:\n\n'.format(i))
|
||||
|
||||
file.write('\n\n'.format(i))
|
||||
|
||||
file.write('[Bill of Materials](tutorial{:02d}.bom.tsv)\n\n\n'.format(i))
|
||||
239
src/wireviz/wireviz.py
Executable file
@ -0,0 +1,239 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
import yaml
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
|
||||
|
||||
from wireviz.Harness import Harness
|
||||
|
||||
|
||||
def parse(yaml_input, file_out=None, generate_bom=False):
|
||||
|
||||
yaml_data = yaml.safe_load(yaml_input)
|
||||
|
||||
def expand(yaml_data):
|
||||
# yaml_data can be:
|
||||
# - a singleton (normally str or int)
|
||||
# - a list of str or int
|
||||
# if str is of the format '#-#', it is treated as a range (inclusive) and expanded
|
||||
output = []
|
||||
if not isinstance(yaml_data, list):
|
||||
yaml_data = [yaml_data]
|
||||
for e in yaml_data:
|
||||
e = str(e)
|
||||
if '-' in e: # list of pins
|
||||
a, b = tuple(map(int, e.split('-')))
|
||||
if a < b:
|
||||
for x in range(a, b + 1):
|
||||
output.append(x)
|
||||
elif a > b:
|
||||
for x in range(a, b - 1, -1):
|
||||
output.append(x)
|
||||
elif a == b:
|
||||
output.append(a)
|
||||
else:
|
||||
try:
|
||||
x = int(e)
|
||||
except Exception:
|
||||
x = e
|
||||
output.append(x)
|
||||
return output
|
||||
|
||||
def check_designators(what, where):
|
||||
for i, x in enumerate(what):
|
||||
if x not in yaml_data[where[i]]:
|
||||
return False
|
||||
return True
|
||||
|
||||
harness = Harness()
|
||||
|
||||
# add items
|
||||
sections = ['connectors', 'cables', 'ferrules', 'connections']
|
||||
types = [dict, dict, dict, list]
|
||||
for sec, ty in zip(sections, types):
|
||||
if sec in yaml_data and type(yaml_data[sec]) == ty:
|
||||
if len(yaml_data[sec]) > 0:
|
||||
if ty == dict:
|
||||
for key, o in yaml_data[sec].items():
|
||||
if sec == 'connectors':
|
||||
harness.add_connector(name=key, **o)
|
||||
elif sec == 'cables':
|
||||
harness.add_cable(name=key, **o)
|
||||
elif sec == 'ferrules':
|
||||
pass
|
||||
else:
|
||||
pass # section exists but is empty
|
||||
else: # section does not exist, create empty section
|
||||
if ty == dict:
|
||||
yaml_data[sec] = {}
|
||||
elif ty == list:
|
||||
yaml_data[sec] = []
|
||||
|
||||
# add connections
|
||||
ferrule_counter = 0
|
||||
for connections in yaml_data['connections']:
|
||||
if len(connections) == 3: # format: connector -- cable -- connector
|
||||
|
||||
for connection in connections:
|
||||
if len(list(connection.keys())) != 1: # check that each entry in con has only one key, which is the designator
|
||||
raise Exception('Too many keys')
|
||||
|
||||
from_name = list(connections[0].keys())[0]
|
||||
via_name = list(connections[1].keys())[0]
|
||||
to_name = list(connections[2].keys())[0]
|
||||
|
||||
if not check_designators([from_name, via_name, to_name], ('connectors', 'cables', 'connectors')):
|
||||
print([from_name, via_name, to_name])
|
||||
raise Exception('Bad connection definition (3)')
|
||||
|
||||
from_pins = expand(connections[0][from_name])
|
||||
via_pins = expand(connections[1][via_name])
|
||||
to_pins = expand(connections[2][to_name])
|
||||
|
||||
if len(from_pins) != len(via_pins) or len(via_pins) != len(to_pins):
|
||||
raise Exception('List length mismatch')
|
||||
|
||||
for (from_pin, via_pin, to_pin) in zip(from_pins, via_pins, to_pins):
|
||||
harness.connect(from_name, from_pin, via_name, via_pin, to_name, to_pin)
|
||||
|
||||
elif len(connections) == 2:
|
||||
|
||||
for connection in connections:
|
||||
if type(connection) is dict:
|
||||
if len(list(connection.keys())) != 1: # check that each entry in con has only one key, which is the designator
|
||||
raise Exception('Too many keys')
|
||||
|
||||
# hack to make the format for ferrules compatible with the formats for connectors and cables
|
||||
if type(connections[0]) == str:
|
||||
name = connections[0]
|
||||
connections[0] = {}
|
||||
connections[0][name] = name
|
||||
if type(connections[1]) == str:
|
||||
name = connections[1]
|
||||
connections[1] = {}
|
||||
connections[1][name] = name
|
||||
|
||||
from_name = list(connections[0].keys())[0]
|
||||
to_name = list(connections[1].keys())[0]
|
||||
|
||||
con_cbl = check_designators([from_name, to_name], ('connectors', 'cables'))
|
||||
cbl_con = check_designators([from_name, to_name], ('cables', 'connectors'))
|
||||
con_con = check_designators([from_name, to_name], ('connectors', 'connectors'))
|
||||
|
||||
fer_cbl = check_designators([from_name, to_name], ('ferrules', 'cables'))
|
||||
cbl_fer = check_designators([from_name, to_name], ('cables', 'ferrules'))
|
||||
|
||||
if not con_cbl and not cbl_con and not con_con and not fer_cbl and not cbl_fer:
|
||||
raise Exception('Wrong designators')
|
||||
|
||||
from_pins = expand(connections[0][from_name])
|
||||
to_pins = expand(connections[1][to_name])
|
||||
|
||||
if con_cbl or cbl_con or con_con:
|
||||
if len(from_pins) != len(to_pins):
|
||||
raise Exception('List length mismatch')
|
||||
|
||||
if con_cbl or cbl_con:
|
||||
for (from_pin, to_pin) in zip(from_pins, to_pins):
|
||||
if con_cbl:
|
||||
harness.connect(from_name, from_pin, to_name, to_pin, None, None)
|
||||
else: # cbl_con
|
||||
harness.connect(None, None, from_name, from_pin, to_name, to_pin)
|
||||
elif con_con:
|
||||
cocon_coname = list(connections[0].keys())[0]
|
||||
from_pins = expand(connections[0][from_name])
|
||||
to_pins = expand(connections[1][to_name])
|
||||
|
||||
for (from_pin, to_pin) in zip(from_pins, to_pins):
|
||||
harness.loop(cocon_coname, from_pin, to_pin)
|
||||
if fer_cbl or cbl_fer:
|
||||
from_pins = expand(connections[0][from_name])
|
||||
to_pins = expand(connections[1][to_name])
|
||||
|
||||
if fer_cbl:
|
||||
ferrule_name = from_name
|
||||
cable_name = to_name
|
||||
cable_pins = to_pins
|
||||
else:
|
||||
ferrule_name = to_name
|
||||
cable_name = from_name
|
||||
cable_pins = from_pins
|
||||
|
||||
ferrule_params = yaml_data['ferrules'][ferrule_name]
|
||||
for cable_pin in cable_pins:
|
||||
ferrule_counter = ferrule_counter + 1
|
||||
ferrule_id = f'_F{ferrule_counter}'
|
||||
harness.add_connector(ferrule_id, category='ferrule', **ferrule_params)
|
||||
|
||||
if fer_cbl:
|
||||
harness.connect(ferrule_id, 1, cable_name, cable_pin, None, None)
|
||||
else:
|
||||
harness.connect(None, None, cable_name, cable_pin, ferrule_id, 1)
|
||||
|
||||
else:
|
||||
raise Exception('Wrong number of connection parameters')
|
||||
|
||||
harness.output(filename=file_out, fmt=('png', 'svg'), gen_bom=generate_bom, view=False)
|
||||
|
||||
|
||||
def parse_file(yaml_file, file_out=None, generate_bom=False):
|
||||
with open(yaml_file, 'r') as file:
|
||||
yaml_input = file.read()
|
||||
|
||||
if not file_out:
|
||||
fn, fext = os.path.splitext(yaml_file)
|
||||
file_out = fn
|
||||
file_out = os.path.abspath(file_out)
|
||||
|
||||
parse(yaml_input, file_out=file_out, generate_bom=generate_bom)
|
||||
|
||||
|
||||
def parse_cmdline():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Generate cable and wiring harness documentation from YAML descriptions',
|
||||
)
|
||||
parser.add_argument('input_file', action='store', type=str, metavar='YAML_FILE')
|
||||
parser.add_argument('-o', '--output_file', action='store', type=str, metavar='OUTPUT')
|
||||
parser.add_argument('--generate-bom', action='store_true', default=True)
|
||||
parser.add_argument('--prepend-file', action='store', type=str, metavar='YAML_FILE')
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
args = parse_cmdline()
|
||||
|
||||
if not os.path.exists(args.input_file):
|
||||
print(f'Error: input file {args.input_file} inaccessible or does not exist, check path')
|
||||
sys.exit(1)
|
||||
|
||||
with open(args.input_file) as fh:
|
||||
yaml_input = fh.read()
|
||||
|
||||
if args.prepend_file:
|
||||
if not os.path.exists(args.prepend_file):
|
||||
print(f'Error: prepend input file {args.prepend_file} inaccessible or does not exist, check path')
|
||||
sys.exit(1)
|
||||
with open(args.prepend_file) as fh:
|
||||
prepend = fh.read()
|
||||
yaml_input = prepend + yaml_input
|
||||
|
||||
if not args.output_file:
|
||||
file_out = args.input_file
|
||||
pre, _ = os.path.splitext(file_out)
|
||||
file_out = pre # extension will be added by graphviz output function
|
||||
else:
|
||||
file_out = args.output_file
|
||||
file_out = os.path.abspath(file_out)
|
||||
|
||||
parse(yaml_input, file_out=file_out, generate_bom=args.generate_bom)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
78
src/wireviz/wv_colors.py
Normal file
@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
COLOR_CODES = {
|
||||
'DIN': ['WH', 'BN', 'GN', 'YE', 'GY', 'PK', 'BU', 'RD', 'BK', 'VT'], # ,'GYPK','RDBU','WHGN','BNGN','WHYE','YEBN','WHGY','GYBN','WHPK','PKBN'],
|
||||
'IEC': ['BN', 'RD', 'OG', 'YE', 'GN', 'BU', 'VT', 'GY', 'WH', 'BK'],
|
||||
'BW': ['BK', 'WH'],
|
||||
}
|
||||
|
||||
color_hex = {
|
||||
'BK': '#000000',
|
||||
'WH': '#ffffff',
|
||||
'GY': '#999999',
|
||||
'PK': '#ff66cc',
|
||||
'RD': '#ff0000',
|
||||
'OG': '#ff8000',
|
||||
'YE': '#ffff00',
|
||||
'GN': '#00ff00',
|
||||
'TQ': '#00ffff',
|
||||
'BU': '#0066ff',
|
||||
'VT': '#8000ff',
|
||||
'BN': '#666600',
|
||||
}
|
||||
|
||||
color_full = {
|
||||
'BK': 'black',
|
||||
'WH': 'white',
|
||||
'GY': 'grey',
|
||||
'PK': 'pink',
|
||||
'RD': 'red',
|
||||
'OG': 'orange',
|
||||
'YE': 'yellow',
|
||||
'GN': 'green',
|
||||
'TQ': 'turquoise',
|
||||
'BU': 'blue',
|
||||
'VT': 'violet',
|
||||
'BN': 'brown',
|
||||
}
|
||||
|
||||
color_ger = {
|
||||
'BK': 'sw',
|
||||
'WH': 'ws',
|
||||
'GY': 'gr',
|
||||
'PK': 'rs',
|
||||
'RD': 'rt',
|
||||
'OG': 'or',
|
||||
'YE': 'ge',
|
||||
'GN': 'gn',
|
||||
'TQ': 'tk',
|
||||
'BU': 'bl',
|
||||
'VT': 'vi',
|
||||
'BN': 'br',
|
||||
}
|
||||
|
||||
|
||||
def translate_color(inp, color_mode):
|
||||
if inp == '':
|
||||
output = ''
|
||||
else:
|
||||
if color_mode == 'full':
|
||||
output = color_full[inp].lower()
|
||||
elif color_mode == 'FULL':
|
||||
output = color_full[inp].upper()
|
||||
elif color_mode == 'hex':
|
||||
output = color_hex[inp].lower()
|
||||
elif color_mode == 'HEX':
|
||||
output = color_hex[inp].upper()
|
||||
elif color_mode == 'ger':
|
||||
output = color_ger[inp].lower()
|
||||
elif color_mode == 'GER':
|
||||
output = color_ger[inp].upper()
|
||||
elif color_mode == 'short':
|
||||
output = inp.lower()
|
||||
elif color_mode == 'SHORT':
|
||||
output = inp.upper()
|
||||
else:
|
||||
raise Exception('Unknown color mode')
|
||||
return output
|
||||
67
src/wireviz/wv_helper.py
Normal file
@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from typing import List
|
||||
|
||||
awg_equiv_table = {
|
||||
'0.09': '28',
|
||||
'0.14': '26',
|
||||
'0.25': '24',
|
||||
'0.34': '22',
|
||||
'0.5': '21',
|
||||
'0.75': '20',
|
||||
'1': '18',
|
||||
'1.5': '16',
|
||||
'2.5': '14',
|
||||
'4': '12',
|
||||
'6': '10',
|
||||
'10': '8',
|
||||
'16': '6',
|
||||
'25': '4',
|
||||
'35': '2',
|
||||
'50': '1',
|
||||
}
|
||||
|
||||
mm2_equiv_table = {v:k for k,v in awg_equiv_table.items()}
|
||||
|
||||
def awg_equiv(mm2):
|
||||
return awg_equiv_table.get(str(mm2), 'Unknown')
|
||||
|
||||
def mm2_equiv(awg):
|
||||
return mm2_equiv_table.get(str(awg), 'Unknown')
|
||||
|
||||
def nested(inp):
|
||||
l = []
|
||||
for x in inp:
|
||||
if isinstance(x, list):
|
||||
if len(x) > 0:
|
||||
n = nested(x)
|
||||
if n != '':
|
||||
l.append('{' + n + '}')
|
||||
else:
|
||||
if x is not None:
|
||||
if x != '':
|
||||
l.append(str(x))
|
||||
return '|'.join(l)
|
||||
|
||||
|
||||
def int2tuple(inp):
|
||||
if isinstance(inp, tuple):
|
||||
output = inp
|
||||
else:
|
||||
output = (inp,)
|
||||
return output
|
||||
|
||||
|
||||
def flatten2d(inp):
|
||||
return [[str(item) if not isinstance(item, List) else ', '.join(item) for item in row] for row in inp]
|
||||
|
||||
|
||||
def tuplelist2tsv(inp, header=None):
|
||||
output = ''
|
||||
if header is not None:
|
||||
inp.insert(0, header)
|
||||
inp = flatten2d(inp)
|
||||
for row in inp:
|
||||
output = output + '\t'.join(str(item) for item in row) + '\n'
|
||||
return output
|
||||
@ -1,59 +0,0 @@
|
||||
from typing import Any, List
|
||||
|
||||
def awg_equiv(mm2):
|
||||
awg_equiv_table = {
|
||||
'0.09': 28,
|
||||
'0.14': 26,
|
||||
'0.25': 24,
|
||||
'0.34': 22,
|
||||
'0.5': 21,
|
||||
'0.75': 20,
|
||||
'1': 18,
|
||||
'1.5': 16,
|
||||
'2.5': 14,
|
||||
'4': 12,
|
||||
'6': 10,
|
||||
'10': 8,
|
||||
'16': 6,
|
||||
'25': 4,
|
||||
}
|
||||
k = str(mm2)
|
||||
if k in awg_equiv_table:
|
||||
return awg_equiv_table[k]
|
||||
else:
|
||||
return 'unknown'
|
||||
|
||||
def nested(input):
|
||||
l = []
|
||||
for x in input:
|
||||
if isinstance(x, list):
|
||||
if len(x) > 0:
|
||||
n = nested(x)
|
||||
if n != '':
|
||||
l.append('{' + n + '}')
|
||||
else:
|
||||
if x is not None:
|
||||
if x != '':
|
||||
l.append(str(x))
|
||||
s = '|'.join(l)
|
||||
return s
|
||||
|
||||
def int2tuple(input):
|
||||
if isinstance(input, tuple):
|
||||
output = input
|
||||
else:
|
||||
output = (input,)
|
||||
return output
|
||||
|
||||
def flatten2d(input):
|
||||
output = [[str(item) if not isinstance(item, List) else ', '.join(item) for item in row] for row in input]
|
||||
return output
|
||||
|
||||
def tuplelist2tsv(input, header=None):
|
||||
output = ''
|
||||
if header is not None:
|
||||
input.insert(0, header)
|
||||
input = flatten2d(input)
|
||||
for row in input:
|
||||
output = output + '\t'.join(str(item) for item in row) + '\n'
|
||||
return output
|
||||
@ -1,427 +0,0 @@
|
||||
|
||||
from .error import *
|
||||
|
||||
from .tokens import *
|
||||
from .events import *
|
||||
from .nodes import *
|
||||
|
||||
from .loader import *
|
||||
from .dumper import *
|
||||
|
||||
__version__ = '5.3.1'
|
||||
try:
|
||||
from .cyaml import *
|
||||
__with_libyaml__ = True
|
||||
except ImportError:
|
||||
__with_libyaml__ = False
|
||||
|
||||
import io
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Warnings control
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# 'Global' warnings state:
|
||||
_warnings_enabled = {
|
||||
'YAMLLoadWarning': True,
|
||||
}
|
||||
|
||||
# Get or set global warnings' state
|
||||
def warnings(settings=None):
|
||||
if settings is None:
|
||||
return _warnings_enabled
|
||||
|
||||
if type(settings) is dict:
|
||||
for key in settings:
|
||||
if key in _warnings_enabled:
|
||||
_warnings_enabled[key] = settings[key]
|
||||
|
||||
# Warn when load() is called without Loader=...
|
||||
class YAMLLoadWarning(RuntimeWarning):
|
||||
pass
|
||||
|
||||
def load_warning(method):
|
||||
if _warnings_enabled['YAMLLoadWarning'] is False:
|
||||
return
|
||||
|
||||
import warnings
|
||||
|
||||
message = (
|
||||
"calling yaml.%s() without Loader=... is deprecated, as the "
|
||||
"default Loader is unsafe. Please read "
|
||||
"https://msg.pyyaml.org/load for full details."
|
||||
) % method
|
||||
|
||||
warnings.warn(message, YAMLLoadWarning, stacklevel=3)
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
def scan(stream, Loader=Loader):
|
||||
"""
|
||||
Scan a YAML stream and produce scanning tokens.
|
||||
"""
|
||||
loader = Loader(stream)
|
||||
try:
|
||||
while loader.check_token():
|
||||
yield loader.get_token()
|
||||
finally:
|
||||
loader.dispose()
|
||||
|
||||
def parse(stream, Loader=Loader):
|
||||
"""
|
||||
Parse a YAML stream and produce parsing events.
|
||||
"""
|
||||
loader = Loader(stream)
|
||||
try:
|
||||
while loader.check_event():
|
||||
yield loader.get_event()
|
||||
finally:
|
||||
loader.dispose()
|
||||
|
||||
def compose(stream, Loader=Loader):
|
||||
"""
|
||||
Parse the first YAML document in a stream
|
||||
and produce the corresponding representation tree.
|
||||
"""
|
||||
loader = Loader(stream)
|
||||
try:
|
||||
return loader.get_single_node()
|
||||
finally:
|
||||
loader.dispose()
|
||||
|
||||
def compose_all(stream, Loader=Loader):
|
||||
"""
|
||||
Parse all YAML documents in a stream
|
||||
and produce corresponding representation trees.
|
||||
"""
|
||||
loader = Loader(stream)
|
||||
try:
|
||||
while loader.check_node():
|
||||
yield loader.get_node()
|
||||
finally:
|
||||
loader.dispose()
|
||||
|
||||
def load(stream, Loader=None):
|
||||
"""
|
||||
Parse the first YAML document in a stream
|
||||
and produce the corresponding Python object.
|
||||
"""
|
||||
if Loader is None:
|
||||
load_warning('load')
|
||||
Loader = FullLoader
|
||||
|
||||
loader = Loader(stream)
|
||||
try:
|
||||
return loader.get_single_data()
|
||||
finally:
|
||||
loader.dispose()
|
||||
|
||||
def load_all(stream, Loader=None):
|
||||
"""
|
||||
Parse all YAML documents in a stream
|
||||
and produce corresponding Python objects.
|
||||
"""
|
||||
if Loader is None:
|
||||
load_warning('load_all')
|
||||
Loader = FullLoader
|
||||
|
||||
loader = Loader(stream)
|
||||
try:
|
||||
while loader.check_data():
|
||||
yield loader.get_data()
|
||||
finally:
|
||||
loader.dispose()
|
||||
|
||||
def full_load(stream):
|
||||
"""
|
||||
Parse the first YAML document in a stream
|
||||
and produce the corresponding Python object.
|
||||
|
||||
Resolve all tags except those known to be
|
||||
unsafe on untrusted input.
|
||||
"""
|
||||
return load(stream, FullLoader)
|
||||
|
||||
def full_load_all(stream):
|
||||
"""
|
||||
Parse all YAML documents in a stream
|
||||
and produce corresponding Python objects.
|
||||
|
||||
Resolve all tags except those known to be
|
||||
unsafe on untrusted input.
|
||||
"""
|
||||
return load_all(stream, FullLoader)
|
||||
|
||||
def safe_load(stream):
|
||||
"""
|
||||
Parse the first YAML document in a stream
|
||||
and produce the corresponding Python object.
|
||||
|
||||
Resolve only basic YAML tags. This is known
|
||||
to be safe for untrusted input.
|
||||
"""
|
||||
return load(stream, SafeLoader)
|
||||
|
||||
def safe_load_all(stream):
|
||||
"""
|
||||
Parse all YAML documents in a stream
|
||||
and produce corresponding Python objects.
|
||||
|
||||
Resolve only basic YAML tags. This is known
|
||||
to be safe for untrusted input.
|
||||
"""
|
||||
return load_all(stream, SafeLoader)
|
||||
|
||||
def unsafe_load(stream):
|
||||
"""
|
||||
Parse the first YAML document in a stream
|
||||
and produce the corresponding Python object.
|
||||
|
||||
Resolve all tags, even those known to be
|
||||
unsafe on untrusted input.
|
||||
"""
|
||||
return load(stream, UnsafeLoader)
|
||||
|
||||
def unsafe_load_all(stream):
|
||||
"""
|
||||
Parse all YAML documents in a stream
|
||||
and produce corresponding Python objects.
|
||||
|
||||
Resolve all tags, even those known to be
|
||||
unsafe on untrusted input.
|
||||
"""
|
||||
return load_all(stream, UnsafeLoader)
|
||||
|
||||
def emit(events, stream=None, Dumper=Dumper,
|
||||
canonical=None, indent=None, width=None,
|
||||
allow_unicode=None, line_break=None):
|
||||
"""
|
||||
Emit YAML parsing events into a stream.
|
||||
If stream is None, return the produced string instead.
|
||||
"""
|
||||
getvalue = None
|
||||
if stream is None:
|
||||
stream = io.StringIO()
|
||||
getvalue = stream.getvalue
|
||||
dumper = Dumper(stream, canonical=canonical, indent=indent, width=width,
|
||||
allow_unicode=allow_unicode, line_break=line_break)
|
||||
try:
|
||||
for event in events:
|
||||
dumper.emit(event)
|
||||
finally:
|
||||
dumper.dispose()
|
||||
if getvalue:
|
||||
return getvalue()
|
||||
|
||||
def serialize_all(nodes, stream=None, Dumper=Dumper,
|
||||
canonical=None, indent=None, width=None,
|
||||
allow_unicode=None, line_break=None,
|
||||
encoding=None, explicit_start=None, explicit_end=None,
|
||||
version=None, tags=None):
|
||||
"""
|
||||
Serialize a sequence of representation trees into a YAML stream.
|
||||
If stream is None, return the produced string instead.
|
||||
"""
|
||||
getvalue = None
|
||||
if stream is None:
|
||||
if encoding is None:
|
||||
stream = io.StringIO()
|
||||
else:
|
||||
stream = io.BytesIO()
|
||||
getvalue = stream.getvalue
|
||||
dumper = Dumper(stream, canonical=canonical, indent=indent, width=width,
|
||||
allow_unicode=allow_unicode, line_break=line_break,
|
||||
encoding=encoding, version=version, tags=tags,
|
||||
explicit_start=explicit_start, explicit_end=explicit_end)
|
||||
try:
|
||||
dumper.open()
|
||||
for node in nodes:
|
||||
dumper.serialize(node)
|
||||
dumper.close()
|
||||
finally:
|
||||
dumper.dispose()
|
||||
if getvalue:
|
||||
return getvalue()
|
||||
|
||||
def serialize(node, stream=None, Dumper=Dumper, **kwds):
|
||||
"""
|
||||
Serialize a representation tree into a YAML stream.
|
||||
If stream is None, return the produced string instead.
|
||||
"""
|
||||
return serialize_all([node], stream, Dumper=Dumper, **kwds)
|
||||
|
||||
def dump_all(documents, stream=None, Dumper=Dumper,
|
||||
default_style=None, default_flow_style=False,
|
||||
canonical=None, indent=None, width=None,
|
||||
allow_unicode=None, line_break=None,
|
||||
encoding=None, explicit_start=None, explicit_end=None,
|
||||
version=None, tags=None, sort_keys=True):
|
||||
"""
|
||||
Serialize a sequence of Python objects into a YAML stream.
|
||||
If stream is None, return the produced string instead.
|
||||
"""
|
||||
getvalue = None
|
||||
if stream is None:
|
||||
if encoding is None:
|
||||
stream = io.StringIO()
|
||||
else:
|
||||
stream = io.BytesIO()
|
||||
getvalue = stream.getvalue
|
||||
dumper = Dumper(stream, default_style=default_style,
|
||||
default_flow_style=default_flow_style,
|
||||
canonical=canonical, indent=indent, width=width,
|
||||
allow_unicode=allow_unicode, line_break=line_break,
|
||||
encoding=encoding, version=version, tags=tags,
|
||||
explicit_start=explicit_start, explicit_end=explicit_end, sort_keys=sort_keys)
|
||||
try:
|
||||
dumper.open()
|
||||
for data in documents:
|
||||
dumper.represent(data)
|
||||
dumper.close()
|
||||
finally:
|
||||
dumper.dispose()
|
||||
if getvalue:
|
||||
return getvalue()
|
||||
|
||||
def dump(data, stream=None, Dumper=Dumper, **kwds):
|
||||
"""
|
||||
Serialize a Python object into a YAML stream.
|
||||
If stream is None, return the produced string instead.
|
||||
"""
|
||||
return dump_all([data], stream, Dumper=Dumper, **kwds)
|
||||
|
||||
def safe_dump_all(documents, stream=None, **kwds):
|
||||
"""
|
||||
Serialize a sequence of Python objects into a YAML stream.
|
||||
Produce only basic YAML tags.
|
||||
If stream is None, return the produced string instead.
|
||||
"""
|
||||
return dump_all(documents, stream, Dumper=SafeDumper, **kwds)
|
||||
|
||||
def safe_dump(data, stream=None, **kwds):
|
||||
"""
|
||||
Serialize a Python object into a YAML stream.
|
||||
Produce only basic YAML tags.
|
||||
If stream is None, return the produced string instead.
|
||||
"""
|
||||
return dump_all([data], stream, Dumper=SafeDumper, **kwds)
|
||||
|
||||
def add_implicit_resolver(tag, regexp, first=None,
|
||||
Loader=None, Dumper=Dumper):
|
||||
"""
|
||||
Add an implicit scalar detector.
|
||||
If an implicit scalar value matches the given regexp,
|
||||
the corresponding tag is assigned to the scalar.
|
||||
first is a sequence of possible initial characters or None.
|
||||
"""
|
||||
if Loader is None:
|
||||
loader.Loader.add_implicit_resolver(tag, regexp, first)
|
||||
loader.FullLoader.add_implicit_resolver(tag, regexp, first)
|
||||
loader.UnsafeLoader.add_implicit_resolver(tag, regexp, first)
|
||||
else:
|
||||
Loader.add_implicit_resolver(tag, regexp, first)
|
||||
Dumper.add_implicit_resolver(tag, regexp, first)
|
||||
|
||||
def add_path_resolver(tag, path, kind=None, Loader=None, Dumper=Dumper):
|
||||
"""
|
||||
Add a path based resolver for the given tag.
|
||||
A path is a list of keys that forms a path
|
||||
to a node in the representation tree.
|
||||
Keys can be string values, integers, or None.
|
||||
"""
|
||||
if Loader is None:
|
||||
loader.Loader.add_path_resolver(tag, path, kind)
|
||||
loader.FullLoader.add_path_resolver(tag, path, kind)
|
||||
loader.UnsafeLoader.add_path_resolver(tag, path, kind)
|
||||
else:
|
||||
Loader.add_path_resolver(tag, path, kind)
|
||||
Dumper.add_path_resolver(tag, path, kind)
|
||||
|
||||
def add_constructor(tag, constructor, Loader=None):
|
||||
"""
|
||||
Add a constructor for the given tag.
|
||||
Constructor is a function that accepts a Loader instance
|
||||
and a node object and produces the corresponding Python object.
|
||||
"""
|
||||
if Loader is None:
|
||||
loader.Loader.add_constructor(tag, constructor)
|
||||
loader.FullLoader.add_constructor(tag, constructor)
|
||||
loader.UnsafeLoader.add_constructor(tag, constructor)
|
||||
else:
|
||||
Loader.add_constructor(tag, constructor)
|
||||
|
||||
def add_multi_constructor(tag_prefix, multi_constructor, Loader=None):
|
||||
"""
|
||||
Add a multi-constructor for the given tag prefix.
|
||||
Multi-constructor is called for a node if its tag starts with tag_prefix.
|
||||
Multi-constructor accepts a Loader instance, a tag suffix,
|
||||
and a node object and produces the corresponding Python object.
|
||||
"""
|
||||
if Loader is None:
|
||||
loader.Loader.add_multi_constructor(tag_prefix, multi_constructor)
|
||||
loader.FullLoader.add_multi_constructor(tag_prefix, multi_constructor)
|
||||
loader.UnsafeLoader.add_multi_constructor(tag_prefix, multi_constructor)
|
||||
else:
|
||||
Loader.add_multi_constructor(tag_prefix, multi_constructor)
|
||||
|
||||
def add_representer(data_type, representer, Dumper=Dumper):
|
||||
"""
|
||||
Add a representer for the given type.
|
||||
Representer is a function accepting a Dumper instance
|
||||
and an instance of the given data type
|
||||
and producing the corresponding representation node.
|
||||
"""
|
||||
Dumper.add_representer(data_type, representer)
|
||||
|
||||
def add_multi_representer(data_type, multi_representer, Dumper=Dumper):
|
||||
"""
|
||||
Add a representer for the given type.
|
||||
Multi-representer is a function accepting a Dumper instance
|
||||
and an instance of the given data type or subtype
|
||||
and producing the corresponding representation node.
|
||||
"""
|
||||
Dumper.add_multi_representer(data_type, multi_representer)
|
||||
|
||||
class YAMLObjectMetaclass(type):
|
||||
"""
|
||||
The metaclass for YAMLObject.
|
||||
"""
|
||||
def __init__(cls, name, bases, kwds):
|
||||
super(YAMLObjectMetaclass, cls).__init__(name, bases, kwds)
|
||||
if 'yaml_tag' in kwds and kwds['yaml_tag'] is not None:
|
||||
if isinstance(cls.yaml_loader, list):
|
||||
for loader in cls.yaml_loader:
|
||||
loader.add_constructor(cls.yaml_tag, cls.from_yaml)
|
||||
else:
|
||||
cls.yaml_loader.add_constructor(cls.yaml_tag, cls.from_yaml)
|
||||
|
||||
cls.yaml_dumper.add_representer(cls, cls.to_yaml)
|
||||
|
||||
class YAMLObject(metaclass=YAMLObjectMetaclass):
|
||||
"""
|
||||
An object that can dump itself to a YAML stream
|
||||
and load itself from a YAML stream.
|
||||
"""
|
||||
|
||||
__slots__ = () # no direct instantiation, so allow immutable subclasses
|
||||
|
||||
yaml_loader = [Loader, FullLoader, UnsafeLoader]
|
||||
yaml_dumper = Dumper
|
||||
|
||||
yaml_tag = None
|
||||
yaml_flow_style = None
|
||||
|
||||
@classmethod
|
||||
def from_yaml(cls, loader, node):
|
||||
"""
|
||||
Convert a representation node to a Python object.
|
||||
"""
|
||||
return loader.construct_yaml_object(node, cls)
|
||||
|
||||
@classmethod
|
||||
def to_yaml(cls, dumper, data):
|
||||
"""
|
||||
Convert a Python object to a representation node.
|
||||
"""
|
||||
return dumper.represent_yaml_object(cls.yaml_tag, data, cls,
|
||||
flow_style=cls.yaml_flow_style)
|
||||
|
||||
@ -1,139 +0,0 @@
|
||||
|
||||
__all__ = ['Composer', 'ComposerError']
|
||||
|
||||
from .error import MarkedYAMLError
|
||||
from .events import *
|
||||
from .nodes import *
|
||||
|
||||
class ComposerError(MarkedYAMLError):
|
||||
pass
|
||||
|
||||
class Composer:
|
||||
|
||||
def __init__(self):
|
||||
self.anchors = {}
|
||||
|
||||
def check_node(self):
|
||||
# Drop the STREAM-START event.
|
||||
if self.check_event(StreamStartEvent):
|
||||
self.get_event()
|
||||
|
||||
# If there are more documents available?
|
||||
return not self.check_event(StreamEndEvent)
|
||||
|
||||
def get_node(self):
|
||||
# Get the root node of the next document.
|
||||
if not self.check_event(StreamEndEvent):
|
||||
return self.compose_document()
|
||||
|
||||
def get_single_node(self):
|
||||
# Drop the STREAM-START event.
|
||||
self.get_event()
|
||||
|
||||
# Compose a document if the stream is not empty.
|
||||
document = None
|
||||
if not self.check_event(StreamEndEvent):
|
||||
document = self.compose_document()
|
||||
|
||||
# Ensure that the stream contains no more documents.
|
||||
if not self.check_event(StreamEndEvent):
|
||||
event = self.get_event()
|
||||
raise ComposerError("expected a single document in the stream",
|
||||
document.start_mark, "but found another document",
|
||||
event.start_mark)
|
||||
|
||||
# Drop the STREAM-END event.
|
||||
self.get_event()
|
||||
|
||||
return document
|
||||
|
||||
def compose_document(self):
|
||||
# Drop the DOCUMENT-START event.
|
||||
self.get_event()
|
||||
|
||||
# Compose the root node.
|
||||
node = self.compose_node(None, None)
|
||||
|
||||
# Drop the DOCUMENT-END event.
|
||||
self.get_event()
|
||||
|
||||
self.anchors = {}
|
||||
return node
|
||||
|
||||
def compose_node(self, parent, index):
|
||||
if self.check_event(AliasEvent):
|
||||
event = self.get_event()
|
||||
anchor = event.anchor
|
||||
if anchor not in self.anchors:
|
||||
raise ComposerError(None, None, "found undefined alias %r"
|
||||
% anchor, event.start_mark)
|
||||
return self.anchors[anchor]
|
||||
event = self.peek_event()
|
||||
anchor = event.anchor
|
||||
if anchor is not None:
|
||||
if anchor in self.anchors:
|
||||
raise ComposerError("found duplicate anchor %r; first occurrence"
|
||||
% anchor, self.anchors[anchor].start_mark,
|
||||
"second occurrence", event.start_mark)
|
||||
self.descend_resolver(parent, index)
|
||||
if self.check_event(ScalarEvent):
|
||||
node = self.compose_scalar_node(anchor)
|
||||
elif self.check_event(SequenceStartEvent):
|
||||
node = self.compose_sequence_node(anchor)
|
||||
elif self.check_event(MappingStartEvent):
|
||||
node = self.compose_mapping_node(anchor)
|
||||
self.ascend_resolver()
|
||||
return node
|
||||
|
||||
def compose_scalar_node(self, anchor):
|
||||
event = self.get_event()
|
||||
tag = event.tag
|
||||
if tag is None or tag == '!':
|
||||
tag = self.resolve(ScalarNode, event.value, event.implicit)
|
||||
node = ScalarNode(tag, event.value,
|
||||
event.start_mark, event.end_mark, style=event.style)
|
||||
if anchor is not None:
|
||||
self.anchors[anchor] = node
|
||||
return node
|
||||
|
||||
def compose_sequence_node(self, anchor):
|
||||
start_event = self.get_event()
|
||||
tag = start_event.tag
|
||||
if tag is None or tag == '!':
|
||||
tag = self.resolve(SequenceNode, None, start_event.implicit)
|
||||
node = SequenceNode(tag, [],
|
||||
start_event.start_mark, None,
|
||||
flow_style=start_event.flow_style)
|
||||
if anchor is not None:
|
||||
self.anchors[anchor] = node
|
||||
index = 0
|
||||
while not self.check_event(SequenceEndEvent):
|
||||
node.value.append(self.compose_node(node, index))
|
||||
index += 1
|
||||
end_event = self.get_event()
|
||||
node.end_mark = end_event.end_mark
|
||||
return node
|
||||
|
||||
def compose_mapping_node(self, anchor):
|
||||
start_event = self.get_event()
|
||||
tag = start_event.tag
|
||||
if tag is None or tag == '!':
|
||||
tag = self.resolve(MappingNode, None, start_event.implicit)
|
||||
node = MappingNode(tag, [],
|
||||
start_event.start_mark, None,
|
||||
flow_style=start_event.flow_style)
|
||||
if anchor is not None:
|
||||
self.anchors[anchor] = node
|
||||
while not self.check_event(MappingEndEvent):
|
||||
#key_event = self.peek_event()
|
||||
item_key = self.compose_node(node, None)
|
||||
#if item_key in node.value:
|
||||
# raise ComposerError("while composing a mapping", start_event.start_mark,
|
||||
# "found duplicate key", key_event.start_mark)
|
||||
item_value = self.compose_node(node, item_key)
|
||||
#node.value[item_key] = item_value
|
||||
node.value.append((item_key, item_value))
|
||||
end_event = self.get_event()
|
||||
node.end_mark = end_event.end_mark
|
||||
return node
|
||||
|
||||
@ -1,748 +0,0 @@
|
||||
|
||||
__all__ = [
|
||||
'BaseConstructor',
|
||||
'SafeConstructor',
|
||||
'FullConstructor',
|
||||
'UnsafeConstructor',
|
||||
'Constructor',
|
||||
'ConstructorError'
|
||||
]
|
||||
|
||||
from .error import *
|
||||
from .nodes import *
|
||||
|
||||
import collections.abc, datetime, base64, binascii, re, sys, types
|
||||
|
||||
class ConstructorError(MarkedYAMLError):
|
||||
pass
|
||||
|
||||
class BaseConstructor:
|
||||
|
||||
yaml_constructors = {}
|
||||
yaml_multi_constructors = {}
|
||||
|
||||
def __init__(self):
|
||||
self.constructed_objects = {}
|
||||
self.recursive_objects = {}
|
||||
self.state_generators = []
|
||||
self.deep_construct = False
|
||||
|
||||
def check_data(self):
|
||||
# If there are more documents available?
|
||||
return self.check_node()
|
||||
|
||||
def check_state_key(self, key):
|
||||
"""Block special attributes/methods from being set in a newly created
|
||||
object, to prevent user-controlled methods from being called during
|
||||
deserialization"""
|
||||
if self.get_state_keys_blacklist_regexp().match(key):
|
||||
raise ConstructorError(None, None,
|
||||
"blacklisted key '%s' in instance state found" % (key,), None)
|
||||
|
||||
def get_data(self):
|
||||
# Construct and return the next document.
|
||||
if self.check_node():
|
||||
return self.construct_document(self.get_node())
|
||||
|
||||
def get_single_data(self):
|
||||
# Ensure that the stream contains a single document and construct it.
|
||||
node = self.get_single_node()
|
||||
if node is not None:
|
||||
return self.construct_document(node)
|
||||
return None
|
||||
|
||||
def construct_document(self, node):
|
||||
data = self.construct_object(node)
|
||||
while self.state_generators:
|
||||
state_generators = self.state_generators
|
||||
self.state_generators = []
|
||||
for generator in state_generators:
|
||||
for dummy in generator:
|
||||
pass
|
||||
self.constructed_objects = {}
|
||||
self.recursive_objects = {}
|
||||
self.deep_construct = False
|
||||
return data
|
||||
|
||||
def construct_object(self, node, deep=False):
|
||||
if node in self.constructed_objects:
|
||||
return self.constructed_objects[node]
|
||||
if deep:
|
||||
old_deep = self.deep_construct
|
||||
self.deep_construct = True
|
||||
if node in self.recursive_objects:
|
||||
raise ConstructorError(None, None,
|
||||
"found unconstructable recursive node", node.start_mark)
|
||||
self.recursive_objects[node] = None
|
||||
constructor = None
|
||||
tag_suffix = None
|
||||
if node.tag in self.yaml_constructors:
|
||||
constructor = self.yaml_constructors[node.tag]
|
||||
else:
|
||||
for tag_prefix in self.yaml_multi_constructors:
|
||||
if tag_prefix is not None and node.tag.startswith(tag_prefix):
|
||||
tag_suffix = node.tag[len(tag_prefix):]
|
||||
constructor = self.yaml_multi_constructors[tag_prefix]
|
||||
break
|
||||
else:
|
||||
if None in self.yaml_multi_constructors:
|
||||
tag_suffix = node.tag
|
||||
constructor = self.yaml_multi_constructors[None]
|
||||
elif None in self.yaml_constructors:
|
||||
constructor = self.yaml_constructors[None]
|
||||
elif isinstance(node, ScalarNode):
|
||||
constructor = self.__class__.construct_scalar
|
||||
elif isinstance(node, SequenceNode):
|
||||
constructor = self.__class__.construct_sequence
|
||||
elif isinstance(node, MappingNode):
|
||||
constructor = self.__class__.construct_mapping
|
||||
if tag_suffix is None:
|
||||
data = constructor(self, node)
|
||||
else:
|
||||
data = constructor(self, tag_suffix, node)
|
||||
if isinstance(data, types.GeneratorType):
|
||||
generator = data
|
||||
data = next(generator)
|
||||
if self.deep_construct:
|
||||
for dummy in generator:
|
||||
pass
|
||||
else:
|
||||
self.state_generators.append(generator)
|
||||
self.constructed_objects[node] = data
|
||||
del self.recursive_objects[node]
|
||||
if deep:
|
||||
self.deep_construct = old_deep
|
||||
return data
|
||||
|
||||
def construct_scalar(self, node):
|
||||
if not isinstance(node, ScalarNode):
|
||||
raise ConstructorError(None, None,
|
||||
"expected a scalar node, but found %s" % node.id,
|
||||
node.start_mark)
|
||||
return node.value
|
||||
|
||||
def construct_sequence(self, node, deep=False):
|
||||
if not isinstance(node, SequenceNode):
|
||||
raise ConstructorError(None, None,
|
||||
"expected a sequence node, but found %s" % node.id,
|
||||
node.start_mark)
|
||||
return [self.construct_object(child, deep=deep)
|
||||
for child in node.value]
|
||||
|
||||
def construct_mapping(self, node, deep=False):
|
||||
if not isinstance(node, MappingNode):
|
||||
raise ConstructorError(None, None,
|
||||
"expected a mapping node, but found %s" % node.id,
|
||||
node.start_mark)
|
||||
mapping = {}
|
||||
for key_node, value_node in node.value:
|
||||
key = self.construct_object(key_node, deep=deep)
|
||||
if not isinstance(key, collections.abc.Hashable):
|
||||
raise ConstructorError("while constructing a mapping", node.start_mark,
|
||||
"found unhashable key", key_node.start_mark)
|
||||
value = self.construct_object(value_node, deep=deep)
|
||||
mapping[key] = value
|
||||
return mapping
|
||||
|
||||
def construct_pairs(self, node, deep=False):
|
||||
if not isinstance(node, MappingNode):
|
||||
raise ConstructorError(None, None,
|
||||
"expected a mapping node, but found %s" % node.id,
|
||||
node.start_mark)
|
||||
pairs = []
|
||||
for key_node, value_node in node.value:
|
||||
key = self.construct_object(key_node, deep=deep)
|
||||
value = self.construct_object(value_node, deep=deep)
|
||||
pairs.append((key, value))
|
||||
return pairs
|
||||
|
||||
@classmethod
|
||||
def add_constructor(cls, tag, constructor):
|
||||
if not 'yaml_constructors' in cls.__dict__:
|
||||
cls.yaml_constructors = cls.yaml_constructors.copy()
|
||||
cls.yaml_constructors[tag] = constructor
|
||||
|
||||
@classmethod
|
||||
def add_multi_constructor(cls, tag_prefix, multi_constructor):
|
||||
if not 'yaml_multi_constructors' in cls.__dict__:
|
||||
cls.yaml_multi_constructors = cls.yaml_multi_constructors.copy()
|
||||
cls.yaml_multi_constructors[tag_prefix] = multi_constructor
|
||||
|
||||
class SafeConstructor(BaseConstructor):
|
||||
|
||||
def construct_scalar(self, node):
|
||||
if isinstance(node, MappingNode):
|
||||
for key_node, value_node in node.value:
|
||||
if key_node.tag == 'tag:yaml.org,2002:value':
|
||||
return self.construct_scalar(value_node)
|
||||
return super().construct_scalar(node)
|
||||
|
||||
def flatten_mapping(self, node):
|
||||
merge = []
|
||||
index = 0
|
||||
while index < len(node.value):
|
||||
key_node, value_node = node.value[index]
|
||||
if key_node.tag == 'tag:yaml.org,2002:merge':
|
||||
del node.value[index]
|
||||
if isinstance(value_node, MappingNode):
|
||||
self.flatten_mapping(value_node)
|
||||
merge.extend(value_node.value)
|
||||
elif isinstance(value_node, SequenceNode):
|
||||
submerge = []
|
||||
for subnode in value_node.value:
|
||||
if not isinstance(subnode, MappingNode):
|
||||
raise ConstructorError("while constructing a mapping",
|
||||
node.start_mark,
|
||||
"expected a mapping for merging, but found %s"
|
||||
% subnode.id, subnode.start_mark)
|
||||
self.flatten_mapping(subnode)
|
||||
submerge.append(subnode.value)
|
||||
submerge.reverse()
|
||||
for value in submerge:
|
||||
merge.extend(value)
|
||||
else:
|
||||
raise ConstructorError("while constructing a mapping", node.start_mark,
|
||||
"expected a mapping or list of mappings for merging, but found %s"
|
||||
% value_node.id, value_node.start_mark)
|
||||
elif key_node.tag == 'tag:yaml.org,2002:value':
|
||||
key_node.tag = 'tag:yaml.org,2002:str'
|
||||
index += 1
|
||||
else:
|
||||
index += 1
|
||||
if merge:
|
||||
node.value = merge + node.value
|
||||
|
||||
def construct_mapping(self, node, deep=False):
|
||||
if isinstance(node, MappingNode):
|
||||
self.flatten_mapping(node)
|
||||
return super().construct_mapping(node, deep=deep)
|
||||
|
||||
def construct_yaml_null(self, node):
|
||||
self.construct_scalar(node)
|
||||
return None
|
||||
|
||||
bool_values = {
|
||||
'yes': True,
|
||||
'no': False,
|
||||
'true': True,
|
||||
'false': False,
|
||||
'on': True,
|
||||
'off': False,
|
||||
}
|
||||
|
||||
def construct_yaml_bool(self, node):
|
||||
value = self.construct_scalar(node)
|
||||
return self.bool_values[value.lower()]
|
||||
|
||||
def construct_yaml_int(self, node):
|
||||
value = self.construct_scalar(node)
|
||||
value = value.replace('_', '')
|
||||
sign = +1
|
||||
if value[0] == '-':
|
||||
sign = -1
|
||||
if value[0] in '+-':
|
||||
value = value[1:]
|
||||
if value == '0':
|
||||
return 0
|
||||
elif value.startswith('0b'):
|
||||
return sign*int(value[2:], 2)
|
||||
elif value.startswith('0x'):
|
||||
return sign*int(value[2:], 16)
|
||||
elif value[0] == '0':
|
||||
return sign*int(value, 8)
|
||||
elif ':' in value:
|
||||
digits = [int(part) for part in value.split(':')]
|
||||
digits.reverse()
|
||||
base = 1
|
||||
value = 0
|
||||
for digit in digits:
|
||||
value += digit*base
|
||||
base *= 60
|
||||
return sign*value
|
||||
else:
|
||||
return sign*int(value)
|
||||
|
||||
inf_value = 1e300
|
||||
while inf_value != inf_value*inf_value:
|
||||
inf_value *= inf_value
|
||||
nan_value = -inf_value/inf_value # Trying to make a quiet NaN (like C99).
|
||||
|
||||
def construct_yaml_float(self, node):
|
||||
value = self.construct_scalar(node)
|
||||
value = value.replace('_', '').lower()
|
||||
sign = +1
|
||||
if value[0] == '-':
|
||||
sign = -1
|
||||
if value[0] in '+-':
|
||||
value = value[1:]
|
||||
if value == '.inf':
|
||||
return sign*self.inf_value
|
||||
elif value == '.nan':
|
||||
return self.nan_value
|
||||
elif ':' in value:
|
||||
digits = [float(part) for part in value.split(':')]
|
||||
digits.reverse()
|
||||
base = 1
|
||||
value = 0.0
|
||||
for digit in digits:
|
||||
value += digit*base
|
||||
base *= 60
|
||||
return sign*value
|
||||
else:
|
||||
return sign*float(value)
|
||||
|
||||
def construct_yaml_binary(self, node):
|
||||
try:
|
||||
value = self.construct_scalar(node).encode('ascii')
|
||||
except UnicodeEncodeError as exc:
|
||||
raise ConstructorError(None, None,
|
||||
"failed to convert base64 data into ascii: %s" % exc,
|
||||
node.start_mark)
|
||||
try:
|
||||
if hasattr(base64, 'decodebytes'):
|
||||
return base64.decodebytes(value)
|
||||
else:
|
||||
return base64.decodestring(value)
|
||||
except binascii.Error as exc:
|
||||
raise ConstructorError(None, None,
|
||||
"failed to decode base64 data: %s" % exc, node.start_mark)
|
||||
|
||||
timestamp_regexp = re.compile(
|
||||
r'''^(?P<year>[0-9][0-9][0-9][0-9])
|
||||
-(?P<month>[0-9][0-9]?)
|
||||
-(?P<day>[0-9][0-9]?)
|
||||
(?:(?:[Tt]|[ \t]+)
|
||||
(?P<hour>[0-9][0-9]?)
|
||||
:(?P<minute>[0-9][0-9])
|
||||
:(?P<second>[0-9][0-9])
|
||||
(?:\.(?P<fraction>[0-9]*))?
|
||||
(?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
|
||||
(?::(?P<tz_minute>[0-9][0-9]))?))?)?$''', re.X)
|
||||
|
||||
def construct_yaml_timestamp(self, node):
|
||||
value = self.construct_scalar(node)
|
||||
match = self.timestamp_regexp.match(node.value)
|
||||
values = match.groupdict()
|
||||
year = int(values['year'])
|
||||
month = int(values['month'])
|
||||
day = int(values['day'])
|
||||
if not values['hour']:
|
||||
return datetime.date(year, month, day)
|
||||
hour = int(values['hour'])
|
||||
minute = int(values['minute'])
|
||||
second = int(values['second'])
|
||||
fraction = 0
|
||||
tzinfo = None
|
||||
if values['fraction']:
|
||||
fraction = values['fraction'][:6]
|
||||
while len(fraction) < 6:
|
||||
fraction += '0'
|
||||
fraction = int(fraction)
|
||||
if values['tz_sign']:
|
||||
tz_hour = int(values['tz_hour'])
|
||||
tz_minute = int(values['tz_minute'] or 0)
|
||||
delta = datetime.timedelta(hours=tz_hour, minutes=tz_minute)
|
||||
if values['tz_sign'] == '-':
|
||||
delta = -delta
|
||||
tzinfo = datetime.timezone(delta)
|
||||
elif values['tz']:
|
||||
tzinfo = datetime.timezone.utc
|
||||
return datetime.datetime(year, month, day, hour, minute, second, fraction,
|
||||
tzinfo=tzinfo)
|
||||
|
||||
def construct_yaml_omap(self, node):
|
||||
# Note: we do not check for duplicate keys, because it's too
|
||||
# CPU-expensive.
|
||||
omap = []
|
||||
yield omap
|
||||
if not isinstance(node, SequenceNode):
|
||||
raise ConstructorError("while constructing an ordered map", node.start_mark,
|
||||
"expected a sequence, but found %s" % node.id, node.start_mark)
|
||||
for subnode in node.value:
|
||||
if not isinstance(subnode, MappingNode):
|
||||
raise ConstructorError("while constructing an ordered map", node.start_mark,
|
||||
"expected a mapping of length 1, but found %s" % subnode.id,
|
||||
subnode.start_mark)
|
||||
if len(subnode.value) != 1:
|
||||
raise ConstructorError("while constructing an ordered map", node.start_mark,
|
||||
"expected a single mapping item, but found %d items" % len(subnode.value),
|
||||
subnode.start_mark)
|
||||
key_node, value_node = subnode.value[0]
|
||||
key = self.construct_object(key_node)
|
||||
value = self.construct_object(value_node)
|
||||
omap.append((key, value))
|
||||
|
||||
def construct_yaml_pairs(self, node):
|
||||
# Note: the same code as `construct_yaml_omap`.
|
||||
pairs = []
|
||||
yield pairs
|
||||
if not isinstance(node, SequenceNode):
|
||||
raise ConstructorError("while constructing pairs", node.start_mark,
|
||||
"expected a sequence, but found %s" % node.id, node.start_mark)
|
||||
for subnode in node.value:
|
||||
if not isinstance(subnode, MappingNode):
|
||||
raise ConstructorError("while constructing pairs", node.start_mark,
|
||||
"expected a mapping of length 1, but found %s" % subnode.id,
|
||||
subnode.start_mark)
|
||||
if len(subnode.value) != 1:
|
||||
raise ConstructorError("while constructing pairs", node.start_mark,
|
||||
"expected a single mapping item, but found %d items" % len(subnode.value),
|
||||
subnode.start_mark)
|
||||
key_node, value_node = subnode.value[0]
|
||||
key = self.construct_object(key_node)
|
||||
value = self.construct_object(value_node)
|
||||
pairs.append((key, value))
|
||||
|
||||
def construct_yaml_set(self, node):
|
||||
data = set()
|
||||
yield data
|
||||
value = self.construct_mapping(node)
|
||||
data.update(value)
|
||||
|
||||
def construct_yaml_str(self, node):
|
||||
return self.construct_scalar(node)
|
||||
|
||||
def construct_yaml_seq(self, node):
|
||||
data = []
|
||||
yield data
|
||||
data.extend(self.construct_sequence(node))
|
||||
|
||||
def construct_yaml_map(self, node):
|
||||
data = {}
|
||||
yield data
|
||||
value = self.construct_mapping(node)
|
||||
data.update(value)
|
||||
|
||||
def construct_yaml_object(self, node, cls):
|
||||
data = cls.__new__(cls)
|
||||
yield data
|
||||
if hasattr(data, '__setstate__'):
|
||||
state = self.construct_mapping(node, deep=True)
|
||||
data.__setstate__(state)
|
||||
else:
|
||||
state = self.construct_mapping(node)
|
||||
data.__dict__.update(state)
|
||||
|
||||
def construct_undefined(self, node):
|
||||
raise ConstructorError(None, None,
|
||||
"could not determine a constructor for the tag %r" % node.tag,
|
||||
node.start_mark)
|
||||
|
||||
SafeConstructor.add_constructor(
|
||||
'tag:yaml.org,2002:null',
|
||||
SafeConstructor.construct_yaml_null)
|
||||
|
||||
SafeConstructor.add_constructor(
|
||||
'tag:yaml.org,2002:bool',
|
||||
SafeConstructor.construct_yaml_bool)
|
||||
|
||||
SafeConstructor.add_constructor(
|
||||
'tag:yaml.org,2002:int',
|
||||
SafeConstructor.construct_yaml_int)
|
||||
|
||||
SafeConstructor.add_constructor(
|
||||
'tag:yaml.org,2002:float',
|
||||
SafeConstructor.construct_yaml_float)
|
||||
|
||||
SafeConstructor.add_constructor(
|
||||
'tag:yaml.org,2002:binary',
|
||||
SafeConstructor.construct_yaml_binary)
|
||||
|
||||
SafeConstructor.add_constructor(
|
||||
'tag:yaml.org,2002:timestamp',
|
||||
SafeConstructor.construct_yaml_timestamp)
|
||||
|
||||
SafeConstructor.add_constructor(
|
||||
'tag:yaml.org,2002:omap',
|
||||
SafeConstructor.construct_yaml_omap)
|
||||
|
||||
SafeConstructor.add_constructor(
|
||||
'tag:yaml.org,2002:pairs',
|
||||
SafeConstructor.construct_yaml_pairs)
|
||||
|
||||
SafeConstructor.add_constructor(
|
||||
'tag:yaml.org,2002:set',
|
||||
SafeConstructor.construct_yaml_set)
|
||||
|
||||
SafeConstructor.add_constructor(
|
||||
'tag:yaml.org,2002:str',
|
||||
SafeConstructor.construct_yaml_str)
|
||||
|
||||
SafeConstructor.add_constructor(
|
||||
'tag:yaml.org,2002:seq',
|
||||
SafeConstructor.construct_yaml_seq)
|
||||
|
||||
SafeConstructor.add_constructor(
|
||||
'tag:yaml.org,2002:map',
|
||||
SafeConstructor.construct_yaml_map)
|
||||
|
||||
SafeConstructor.add_constructor(None,
|
||||
SafeConstructor.construct_undefined)
|
||||
|
||||
class FullConstructor(SafeConstructor):
|
||||
# 'extend' is blacklisted because it is used by
|
||||
# construct_python_object_apply to add `listitems` to a newly generate
|
||||
# python instance
|
||||
def get_state_keys_blacklist(self):
|
||||
return ['^extend$', '^__.*__$']
|
||||
|
||||
def get_state_keys_blacklist_regexp(self):
|
||||
if not hasattr(self, 'state_keys_blacklist_regexp'):
|
||||
self.state_keys_blacklist_regexp = re.compile('(' + '|'.join(self.get_state_keys_blacklist()) + ')')
|
||||
return self.state_keys_blacklist_regexp
|
||||
|
||||
def construct_python_str(self, node):
|
||||
return self.construct_scalar(node)
|
||||
|
||||
def construct_python_unicode(self, node):
|
||||
return self.construct_scalar(node)
|
||||
|
||||
def construct_python_bytes(self, node):
|
||||
try:
|
||||
value = self.construct_scalar(node).encode('ascii')
|
||||
except UnicodeEncodeError as exc:
|
||||
raise ConstructorError(None, None,
|
||||
"failed to convert base64 data into ascii: %s" % exc,
|
||||
node.start_mark)
|
||||
try:
|
||||
if hasattr(base64, 'decodebytes'):
|
||||
return base64.decodebytes(value)
|
||||
else:
|
||||
return base64.decodestring(value)
|
||||
except binascii.Error as exc:
|
||||
raise ConstructorError(None, None,
|
||||
"failed to decode base64 data: %s" % exc, node.start_mark)
|
||||
|
||||
def construct_python_long(self, node):
|
||||
return self.construct_yaml_int(node)
|
||||
|
||||
def construct_python_complex(self, node):
|
||||
return complex(self.construct_scalar(node))
|
||||
|
||||
def construct_python_tuple(self, node):
|
||||
return tuple(self.construct_sequence(node))
|
||||
|
||||
def find_python_module(self, name, mark, unsafe=False):
|
||||
if not name:
|
||||
raise ConstructorError("while constructing a Python module", mark,
|
||||
"expected non-empty name appended to the tag", mark)
|
||||
if unsafe:
|
||||
try:
|
||||
__import__(name)
|
||||
except ImportError as exc:
|
||||
raise ConstructorError("while constructing a Python module", mark,
|
||||
"cannot find module %r (%s)" % (name, exc), mark)
|
||||
if name not in sys.modules:
|
||||
raise ConstructorError("while constructing a Python module", mark,
|
||||
"module %r is not imported" % name, mark)
|
||||
return sys.modules[name]
|
||||
|
||||
def find_python_name(self, name, mark, unsafe=False):
|
||||
if not name:
|
||||
raise ConstructorError("while constructing a Python object", mark,
|
||||
"expected non-empty name appended to the tag", mark)
|
||||
if '.' in name:
|
||||
module_name, object_name = name.rsplit('.', 1)
|
||||
else:
|
||||
module_name = 'builtins'
|
||||
object_name = name
|
||||
if unsafe:
|
||||
try:
|
||||
__import__(module_name)
|
||||
except ImportError as exc:
|
||||
raise ConstructorError("while constructing a Python object", mark,
|
||||
"cannot find module %r (%s)" % (module_name, exc), mark)
|
||||
if module_name not in sys.modules:
|
||||
raise ConstructorError("while constructing a Python object", mark,
|
||||
"module %r is not imported" % module_name, mark)
|
||||
module = sys.modules[module_name]
|
||||
if not hasattr(module, object_name):
|
||||
raise ConstructorError("while constructing a Python object", mark,
|
||||
"cannot find %r in the module %r"
|
||||
% (object_name, module.__name__), mark)
|
||||
return getattr(module, object_name)
|
||||
|
||||
def construct_python_name(self, suffix, node):
|
||||
value = self.construct_scalar(node)
|
||||
if value:
|
||||
raise ConstructorError("while constructing a Python name", node.start_mark,
|
||||
"expected the empty value, but found %r" % value, node.start_mark)
|
||||
return self.find_python_name(suffix, node.start_mark)
|
||||
|
||||
def construct_python_module(self, suffix, node):
|
||||
value = self.construct_scalar(node)
|
||||
if value:
|
||||
raise ConstructorError("while constructing a Python module", node.start_mark,
|
||||
"expected the empty value, but found %r" % value, node.start_mark)
|
||||
return self.find_python_module(suffix, node.start_mark)
|
||||
|
||||
def make_python_instance(self, suffix, node,
|
||||
args=None, kwds=None, newobj=False, unsafe=False):
|
||||
if not args:
|
||||
args = []
|
||||
if not kwds:
|
||||
kwds = {}
|
||||
cls = self.find_python_name(suffix, node.start_mark)
|
||||
if not (unsafe or isinstance(cls, type)):
|
||||
raise ConstructorError("while constructing a Python instance", node.start_mark,
|
||||
"expected a class, but found %r" % type(cls),
|
||||
node.start_mark)
|
||||
if newobj and isinstance(cls, type):
|
||||
return cls.__new__(cls, *args, **kwds)
|
||||
else:
|
||||
return cls(*args, **kwds)
|
||||
|
||||
def set_python_instance_state(self, instance, state, unsafe=False):
|
||||
if hasattr(instance, '__setstate__'):
|
||||
instance.__setstate__(state)
|
||||
else:
|
||||
slotstate = {}
|
||||
if isinstance(state, tuple) and len(state) == 2:
|
||||
state, slotstate = state
|
||||
if hasattr(instance, '__dict__'):
|
||||
if not unsafe and state:
|
||||
for key in state.keys():
|
||||
self.check_state_key(key)
|
||||
instance.__dict__.update(state)
|
||||
elif state:
|
||||
slotstate.update(state)
|
||||
for key, value in slotstate.items():
|
||||
if not unsafe:
|
||||
self.check_state_key(key)
|
||||
setattr(instance, key, value)
|
||||
|
||||
def construct_python_object(self, suffix, node):
|
||||
# Format:
|
||||
# !!python/object:module.name { ... state ... }
|
||||
instance = self.make_python_instance(suffix, node, newobj=True)
|
||||
yield instance
|
||||
deep = hasattr(instance, '__setstate__')
|
||||
state = self.construct_mapping(node, deep=deep)
|
||||
self.set_python_instance_state(instance, state)
|
||||
|
||||
def construct_python_object_apply(self, suffix, node, newobj=False):
|
||||
# Format:
|
||||
# !!python/object/apply # (or !!python/object/new)
|
||||
# args: [ ... arguments ... ]
|
||||
# kwds: { ... keywords ... }
|
||||
# state: ... state ...
|
||||
# listitems: [ ... listitems ... ]
|
||||
# dictitems: { ... dictitems ... }
|
||||
# or short format:
|
||||
# !!python/object/apply [ ... arguments ... ]
|
||||
# The difference between !!python/object/apply and !!python/object/new
|
||||
# is how an object is created, check make_python_instance for details.
|
||||
if isinstance(node, SequenceNode):
|
||||
args = self.construct_sequence(node, deep=True)
|
||||
kwds = {}
|
||||
state = {}
|
||||
listitems = []
|
||||
dictitems = {}
|
||||
else:
|
||||
value = self.construct_mapping(node, deep=True)
|
||||
args = value.get('args', [])
|
||||
kwds = value.get('kwds', {})
|
||||
state = value.get('state', {})
|
||||
listitems = value.get('listitems', [])
|
||||
dictitems = value.get('dictitems', {})
|
||||
instance = self.make_python_instance(suffix, node, args, kwds, newobj)
|
||||
if state:
|
||||
self.set_python_instance_state(instance, state)
|
||||
if listitems:
|
||||
instance.extend(listitems)
|
||||
if dictitems:
|
||||
for key in dictitems:
|
||||
instance[key] = dictitems[key]
|
||||
return instance
|
||||
|
||||
def construct_python_object_new(self, suffix, node):
|
||||
return self.construct_python_object_apply(suffix, node, newobj=True)
|
||||
|
||||
FullConstructor.add_constructor(
|
||||
'tag:yaml.org,2002:python/none',
|
||||
FullConstructor.construct_yaml_null)
|
||||
|
||||
FullConstructor.add_constructor(
|
||||
'tag:yaml.org,2002:python/bool',
|
||||
FullConstructor.construct_yaml_bool)
|
||||
|
||||
FullConstructor.add_constructor(
|
||||
'tag:yaml.org,2002:python/str',
|
||||
FullConstructor.construct_python_str)
|
||||
|
||||
FullConstructor.add_constructor(
|
||||
'tag:yaml.org,2002:python/unicode',
|
||||
FullConstructor.construct_python_unicode)
|
||||
|
||||
FullConstructor.add_constructor(
|
||||
'tag:yaml.org,2002:python/bytes',
|
||||
FullConstructor.construct_python_bytes)
|
||||
|
||||
FullConstructor.add_constructor(
|
||||
'tag:yaml.org,2002:python/int',
|
||||
FullConstructor.construct_yaml_int)
|
||||
|
||||
FullConstructor.add_constructor(
|
||||
'tag:yaml.org,2002:python/long',
|
||||
FullConstructor.construct_python_long)
|
||||
|
||||
FullConstructor.add_constructor(
|
||||
'tag:yaml.org,2002:python/float',
|
||||
FullConstructor.construct_yaml_float)
|
||||
|
||||
FullConstructor.add_constructor(
|
||||
'tag:yaml.org,2002:python/complex',
|
||||
FullConstructor.construct_python_complex)
|
||||
|
||||
FullConstructor.add_constructor(
|
||||
'tag:yaml.org,2002:python/list',
|
||||
FullConstructor.construct_yaml_seq)
|
||||
|
||||
FullConstructor.add_constructor(
|
||||
'tag:yaml.org,2002:python/tuple',
|
||||
FullConstructor.construct_python_tuple)
|
||||
|
||||
FullConstructor.add_constructor(
|
||||
'tag:yaml.org,2002:python/dict',
|
||||
FullConstructor.construct_yaml_map)
|
||||
|
||||
FullConstructor.add_multi_constructor(
|
||||
'tag:yaml.org,2002:python/name:',
|
||||
FullConstructor.construct_python_name)
|
||||
|
||||
FullConstructor.add_multi_constructor(
|
||||
'tag:yaml.org,2002:python/module:',
|
||||
FullConstructor.construct_python_module)
|
||||
|
||||
FullConstructor.add_multi_constructor(
|
||||
'tag:yaml.org,2002:python/object:',
|
||||
FullConstructor.construct_python_object)
|
||||
|
||||
FullConstructor.add_multi_constructor(
|
||||
'tag:yaml.org,2002:python/object/new:',
|
||||
FullConstructor.construct_python_object_new)
|
||||
|
||||
class UnsafeConstructor(FullConstructor):
|
||||
|
||||
def find_python_module(self, name, mark):
|
||||
return super(UnsafeConstructor, self).find_python_module(name, mark, unsafe=True)
|
||||
|
||||
def find_python_name(self, name, mark):
|
||||
return super(UnsafeConstructor, self).find_python_name(name, mark, unsafe=True)
|
||||
|
||||
def make_python_instance(self, suffix, node, args=None, kwds=None, newobj=False):
|
||||
return super(UnsafeConstructor, self).make_python_instance(
|
||||
suffix, node, args, kwds, newobj, unsafe=True)
|
||||
|
||||
def set_python_instance_state(self, instance, state):
|
||||
return super(UnsafeConstructor, self).set_python_instance_state(
|
||||
instance, state, unsafe=True)
|
||||
|
||||
UnsafeConstructor.add_multi_constructor(
|
||||
'tag:yaml.org,2002:python/object/apply:',
|
||||
UnsafeConstructor.construct_python_object_apply)
|
||||
|
||||
# Constructor is same as UnsafeConstructor. Need to leave this in place in case
|
||||
# people have extended it directly.
|
||||
class Constructor(UnsafeConstructor):
|
||||
pass
|
||||
@ -1,101 +0,0 @@
|
||||
|
||||
__all__ = [
|
||||
'CBaseLoader', 'CSafeLoader', 'CFullLoader', 'CUnsafeLoader', 'CLoader',
|
||||
'CBaseDumper', 'CSafeDumper', 'CDumper'
|
||||
]
|
||||
|
||||
from _yaml import CParser, CEmitter
|
||||
|
||||
from .constructor import *
|
||||
|
||||
from .serializer import *
|
||||
from .representer import *
|
||||
|
||||
from .resolver import *
|
||||
|
||||
class CBaseLoader(CParser, BaseConstructor, BaseResolver):
|
||||
|
||||
def __init__(self, stream):
|
||||
CParser.__init__(self, stream)
|
||||
BaseConstructor.__init__(self)
|
||||
BaseResolver.__init__(self)
|
||||
|
||||
class CSafeLoader(CParser, SafeConstructor, Resolver):
|
||||
|
||||
def __init__(self, stream):
|
||||
CParser.__init__(self, stream)
|
||||
SafeConstructor.__init__(self)
|
||||
Resolver.__init__(self)
|
||||
|
||||
class CFullLoader(CParser, FullConstructor, Resolver):
|
||||
|
||||
def __init__(self, stream):
|
||||
CParser.__init__(self, stream)
|
||||
FullConstructor.__init__(self)
|
||||
Resolver.__init__(self)
|
||||
|
||||
class CUnsafeLoader(CParser, UnsafeConstructor, Resolver):
|
||||
|
||||
def __init__(self, stream):
|
||||
CParser.__init__(self, stream)
|
||||
UnsafeConstructor.__init__(self)
|
||||
Resolver.__init__(self)
|
||||
|
||||
class CLoader(CParser, Constructor, Resolver):
|
||||
|
||||
def __init__(self, stream):
|
||||
CParser.__init__(self, stream)
|
||||
Constructor.__init__(self)
|
||||
Resolver.__init__(self)
|
||||
|
||||
class CBaseDumper(CEmitter, BaseRepresenter, BaseResolver):
|
||||
|
||||
def __init__(self, stream,
|
||||
default_style=None, default_flow_style=False,
|
||||
canonical=None, indent=None, width=None,
|
||||
allow_unicode=None, line_break=None,
|
||||
encoding=None, explicit_start=None, explicit_end=None,
|
||||
version=None, tags=None, sort_keys=True):
|
||||
CEmitter.__init__(self, stream, canonical=canonical,
|
||||
indent=indent, width=width, encoding=encoding,
|
||||
allow_unicode=allow_unicode, line_break=line_break,
|
||||
explicit_start=explicit_start, explicit_end=explicit_end,
|
||||
version=version, tags=tags)
|
||||
Representer.__init__(self, default_style=default_style,
|
||||
default_flow_style=default_flow_style, sort_keys=sort_keys)
|
||||
Resolver.__init__(self)
|
||||
|
||||
class CSafeDumper(CEmitter, SafeRepresenter, Resolver):
|
||||
|
||||
def __init__(self, stream,
|
||||
default_style=None, default_flow_style=False,
|
||||
canonical=None, indent=None, width=None,
|
||||
allow_unicode=None, line_break=None,
|
||||
encoding=None, explicit_start=None, explicit_end=None,
|
||||
version=None, tags=None, sort_keys=True):
|
||||
CEmitter.__init__(self, stream, canonical=canonical,
|
||||
indent=indent, width=width, encoding=encoding,
|
||||
allow_unicode=allow_unicode, line_break=line_break,
|
||||
explicit_start=explicit_start, explicit_end=explicit_end,
|
||||
version=version, tags=tags)
|
||||
SafeRepresenter.__init__(self, default_style=default_style,
|
||||
default_flow_style=default_flow_style, sort_keys=sort_keys)
|
||||
Resolver.__init__(self)
|
||||
|
||||
class CDumper(CEmitter, Serializer, Representer, Resolver):
|
||||
|
||||
def __init__(self, stream,
|
||||
default_style=None, default_flow_style=False,
|
||||
canonical=None, indent=None, width=None,
|
||||
allow_unicode=None, line_break=None,
|
||||
encoding=None, explicit_start=None, explicit_end=None,
|
||||
version=None, tags=None, sort_keys=True):
|
||||
CEmitter.__init__(self, stream, canonical=canonical,
|
||||
indent=indent, width=width, encoding=encoding,
|
||||
allow_unicode=allow_unicode, line_break=line_break,
|
||||
explicit_start=explicit_start, explicit_end=explicit_end,
|
||||
version=version, tags=tags)
|
||||
Representer.__init__(self, default_style=default_style,
|
||||
default_flow_style=default_flow_style, sort_keys=sort_keys)
|
||||
Resolver.__init__(self)
|
||||
|
||||
@ -1,62 +0,0 @@
|
||||
|
||||
__all__ = ['BaseDumper', 'SafeDumper', 'Dumper']
|
||||
|
||||
from .emitter import *
|
||||
from .serializer import *
|
||||
from .representer import *
|
||||
from .resolver import *
|
||||
|
||||
class BaseDumper(Emitter, Serializer, BaseRepresenter, BaseResolver):
|
||||
|
||||
def __init__(self, stream,
|
||||
default_style=None, default_flow_style=False,
|
||||
canonical=None, indent=None, width=None,
|
||||
allow_unicode=None, line_break=None,
|
||||
encoding=None, explicit_start=None, explicit_end=None,
|
||||
version=None, tags=None, sort_keys=True):
|
||||
Emitter.__init__(self, stream, canonical=canonical,
|
||||
indent=indent, width=width,
|
||||
allow_unicode=allow_unicode, line_break=line_break)
|
||||
Serializer.__init__(self, encoding=encoding,
|
||||
explicit_start=explicit_start, explicit_end=explicit_end,
|
||||
version=version, tags=tags)
|
||||
Representer.__init__(self, default_style=default_style,
|
||||
default_flow_style=default_flow_style, sort_keys=sort_keys)
|
||||
Resolver.__init__(self)
|
||||
|
||||
class SafeDumper(Emitter, Serializer, SafeRepresenter, Resolver):
|
||||
|
||||
def __init__(self, stream,
|
||||
default_style=None, default_flow_style=False,
|
||||
canonical=None, indent=None, width=None,
|
||||
allow_unicode=None, line_break=None,
|
||||
encoding=None, explicit_start=None, explicit_end=None,
|
||||
version=None, tags=None, sort_keys=True):
|
||||
Emitter.__init__(self, stream, canonical=canonical,
|
||||
indent=indent, width=width,
|
||||
allow_unicode=allow_unicode, line_break=line_break)
|
||||
Serializer.__init__(self, encoding=encoding,
|
||||
explicit_start=explicit_start, explicit_end=explicit_end,
|
||||
version=version, tags=tags)
|
||||
SafeRepresenter.__init__(self, default_style=default_style,
|
||||
default_flow_style=default_flow_style, sort_keys=sort_keys)
|
||||
Resolver.__init__(self)
|
||||
|
||||
class Dumper(Emitter, Serializer, Representer, Resolver):
|
||||
|
||||
def __init__(self, stream,
|
||||
default_style=None, default_flow_style=False,
|
||||
canonical=None, indent=None, width=None,
|
||||
allow_unicode=None, line_break=None,
|
||||
encoding=None, explicit_start=None, explicit_end=None,
|
||||
version=None, tags=None, sort_keys=True):
|
||||
Emitter.__init__(self, stream, canonical=canonical,
|
||||
indent=indent, width=width,
|
||||
allow_unicode=allow_unicode, line_break=line_break)
|
||||
Serializer.__init__(self, encoding=encoding,
|
||||
explicit_start=explicit_start, explicit_end=explicit_end,
|
||||
version=version, tags=tags)
|
||||
Representer.__init__(self, default_style=default_style,
|
||||
default_flow_style=default_flow_style, sort_keys=sort_keys)
|
||||
Resolver.__init__(self)
|
||||
|
||||
1137
src/yaml/emitter.py
@ -1,75 +0,0 @@
|
||||
|
||||
__all__ = ['Mark', 'YAMLError', 'MarkedYAMLError']
|
||||
|
||||
class Mark:
|
||||
|
||||
def __init__(self, name, index, line, column, buffer, pointer):
|
||||
self.name = name
|
||||
self.index = index
|
||||
self.line = line
|
||||
self.column = column
|
||||
self.buffer = buffer
|
||||
self.pointer = pointer
|
||||
|
||||
def get_snippet(self, indent=4, max_length=75):
|
||||
if self.buffer is None:
|
||||
return None
|
||||
head = ''
|
||||
start = self.pointer
|
||||
while start > 0 and self.buffer[start-1] not in '\0\r\n\x85\u2028\u2029':
|
||||
start -= 1
|
||||
if self.pointer-start > max_length/2-1:
|
||||
head = ' ... '
|
||||
start += 5
|
||||
break
|
||||
tail = ''
|
||||
end = self.pointer
|
||||
while end < len(self.buffer) and self.buffer[end] not in '\0\r\n\x85\u2028\u2029':
|
||||
end += 1
|
||||
if end-self.pointer > max_length/2-1:
|
||||
tail = ' ... '
|
||||
end -= 5
|
||||
break
|
||||
snippet = self.buffer[start:end]
|
||||
return ' '*indent + head + snippet + tail + '\n' \
|
||||
+ ' '*(indent+self.pointer-start+len(head)) + '^'
|
||||
|
||||
def __str__(self):
|
||||
snippet = self.get_snippet()
|
||||
where = " in \"%s\", line %d, column %d" \
|
||||
% (self.name, self.line+1, self.column+1)
|
||||
if snippet is not None:
|
||||
where += ":\n"+snippet
|
||||
return where
|
||||
|
||||
class YAMLError(Exception):
|
||||
pass
|
||||
|
||||
class MarkedYAMLError(YAMLError):
|
||||
|
||||
def __init__(self, context=None, context_mark=None,
|
||||
problem=None, problem_mark=None, note=None):
|
||||
self.context = context
|
||||
self.context_mark = context_mark
|
||||
self.problem = problem
|
||||
self.problem_mark = problem_mark
|
||||
self.note = note
|
||||
|
||||
def __str__(self):
|
||||
lines = []
|
||||
if self.context is not None:
|
||||
lines.append(self.context)
|
||||
if self.context_mark is not None \
|
||||
and (self.problem is None or self.problem_mark is None
|
||||
or self.context_mark.name != self.problem_mark.name
|
||||
or self.context_mark.line != self.problem_mark.line
|
||||
or self.context_mark.column != self.problem_mark.column):
|
||||
lines.append(str(self.context_mark))
|
||||
if self.problem is not None:
|
||||
lines.append(self.problem)
|
||||
if self.problem_mark is not None:
|
||||
lines.append(str(self.problem_mark))
|
||||
if self.note is not None:
|
||||
lines.append(self.note)
|
||||
return '\n'.join(lines)
|
||||
|
||||
@ -1,86 +0,0 @@
|
||||
|
||||
# Abstract classes.
|
||||
|
||||
class Event(object):
|
||||
def __init__(self, start_mark=None, end_mark=None):
|
||||
self.start_mark = start_mark
|
||||
self.end_mark = end_mark
|
||||
def __repr__(self):
|
||||
attributes = [key for key in ['anchor', 'tag', 'implicit', 'value']
|
||||
if hasattr(self, key)]
|
||||
arguments = ', '.join(['%s=%r' % (key, getattr(self, key))
|
||||
for key in attributes])
|
||||
return '%s(%s)' % (self.__class__.__name__, arguments)
|
||||
|
||||
class NodeEvent(Event):
|
||||
def __init__(self, anchor, start_mark=None, end_mark=None):
|
||||
self.anchor = anchor
|
||||
self.start_mark = start_mark
|
||||
self.end_mark = end_mark
|
||||
|
||||
class CollectionStartEvent(NodeEvent):
|
||||
def __init__(self, anchor, tag, implicit, start_mark=None, end_mark=None,
|
||||
flow_style=None):
|
||||
self.anchor = anchor
|
||||
self.tag = tag
|
||||
self.implicit = implicit
|
||||
self.start_mark = start_mark
|
||||
self.end_mark = end_mark
|
||||
self.flow_style = flow_style
|
||||
|
||||
class CollectionEndEvent(Event):
|
||||
pass
|
||||
|
||||
# Implementations.
|
||||
|
||||
class StreamStartEvent(Event):
|
||||
def __init__(self, start_mark=None, end_mark=None, encoding=None):
|
||||
self.start_mark = start_mark
|
||||
self.end_mark = end_mark
|
||||
self.encoding = encoding
|
||||
|
||||
class StreamEndEvent(Event):
|
||||
pass
|
||||
|
||||
class DocumentStartEvent(Event):
|
||||
def __init__(self, start_mark=None, end_mark=None,
|
||||
explicit=None, version=None, tags=None):
|
||||
self.start_mark = start_mark
|
||||
self.end_mark = end_mark
|
||||
self.explicit = explicit
|
||||
self.version = version
|
||||
self.tags = tags
|
||||
|
||||
class DocumentEndEvent(Event):
|
||||
def __init__(self, start_mark=None, end_mark=None,
|
||||
explicit=None):
|
||||
self.start_mark = start_mark
|
||||
self.end_mark = end_mark
|
||||
self.explicit = explicit
|
||||
|
||||
class AliasEvent(NodeEvent):
|
||||
pass
|
||||
|
||||
class ScalarEvent(NodeEvent):
|
||||
def __init__(self, anchor, tag, implicit, value,
|
||||
start_mark=None, end_mark=None, style=None):
|
||||
self.anchor = anchor
|
||||
self.tag = tag
|
||||
self.implicit = implicit
|
||||
self.value = value
|
||||
self.start_mark = start_mark
|
||||
self.end_mark = end_mark
|
||||
self.style = style
|
||||
|
||||
class SequenceStartEvent(CollectionStartEvent):
|
||||
pass
|
||||
|
||||
class SequenceEndEvent(CollectionEndEvent):
|
||||
pass
|
||||
|
||||
class MappingStartEvent(CollectionStartEvent):
|
||||
pass
|
||||
|
||||
class MappingEndEvent(CollectionEndEvent):
|
||||
pass
|
||||
|
||||
@ -1,63 +0,0 @@
|
||||
|
||||
__all__ = ['BaseLoader', 'FullLoader', 'SafeLoader', 'Loader', 'UnsafeLoader']
|
||||
|
||||
from .reader import *
|
||||
from .scanner import *
|
||||
from .parser import *
|
||||
from .composer import *
|
||||
from .constructor import *
|
||||
from .resolver import *
|
||||
|
||||
class BaseLoader(Reader, Scanner, Parser, Composer, BaseConstructor, BaseResolver):
|
||||
|
||||
def __init__(self, stream):
|
||||
Reader.__init__(self, stream)
|
||||
Scanner.__init__(self)
|
||||
Parser.__init__(self)
|
||||
Composer.__init__(self)
|
||||
BaseConstructor.__init__(self)
|
||||
BaseResolver.__init__(self)
|
||||
|
||||
class FullLoader(Reader, Scanner, Parser, Composer, FullConstructor, Resolver):
|
||||
|
||||
def __init__(self, stream):
|
||||
Reader.__init__(self, stream)
|
||||
Scanner.__init__(self)
|
||||
Parser.__init__(self)
|
||||
Composer.__init__(self)
|
||||
FullConstructor.__init__(self)
|
||||
Resolver.__init__(self)
|
||||
|
||||
class SafeLoader(Reader, Scanner, Parser, Composer, SafeConstructor, Resolver):
|
||||
|
||||
def __init__(self, stream):
|
||||
Reader.__init__(self, stream)
|
||||
Scanner.__init__(self)
|
||||
Parser.__init__(self)
|
||||
Composer.__init__(self)
|
||||
SafeConstructor.__init__(self)
|
||||
Resolver.__init__(self)
|
||||
|
||||
class Loader(Reader, Scanner, Parser, Composer, Constructor, Resolver):
|
||||
|
||||
def __init__(self, stream):
|
||||
Reader.__init__(self, stream)
|
||||
Scanner.__init__(self)
|
||||
Parser.__init__(self)
|
||||
Composer.__init__(self)
|
||||
Constructor.__init__(self)
|
||||
Resolver.__init__(self)
|
||||
|
||||
# UnsafeLoader is the same as Loader (which is and was always unsafe on
|
||||
# untrusted input). Use of either Loader or UnsafeLoader should be rare, since
|
||||
# FullLoad should be able to load almost all YAML safely. Loader is left intact
|
||||
# to ensure backwards compatibility.
|
||||
class UnsafeLoader(Reader, Scanner, Parser, Composer, Constructor, Resolver):
|
||||
|
||||
def __init__(self, stream):
|
||||
Reader.__init__(self, stream)
|
||||
Scanner.__init__(self)
|
||||
Parser.__init__(self)
|
||||
Composer.__init__(self)
|
||||
Constructor.__init__(self)
|
||||
Resolver.__init__(self)
|
||||
@ -1,49 +0,0 @@
|
||||
|
||||
class Node(object):
|
||||
def __init__(self, tag, value, start_mark, end_mark):
|
||||
self.tag = tag
|
||||
self.value = value
|
||||
self.start_mark = start_mark
|
||||
self.end_mark = end_mark
|
||||
def __repr__(self):
|
||||
value = self.value
|
||||
#if isinstance(value, list):
|
||||
# if len(value) == 0:
|
||||
# value = '<empty>'
|
||||
# elif len(value) == 1:
|
||||
# value = '<1 item>'
|
||||
# else:
|
||||
# value = '<%d items>' % len(value)
|
||||
#else:
|
||||
# if len(value) > 75:
|
||||
# value = repr(value[:70]+u' ... ')
|
||||
# else:
|
||||
# value = repr(value)
|
||||
value = repr(value)
|
||||
return '%s(tag=%r, value=%s)' % (self.__class__.__name__, self.tag, value)
|
||||
|
||||
class ScalarNode(Node):
|
||||
id = 'scalar'
|
||||
def __init__(self, tag, value,
|
||||
start_mark=None, end_mark=None, style=None):
|
||||
self.tag = tag
|
||||
self.value = value
|
||||
self.start_mark = start_mark
|
||||
self.end_mark = end_mark
|
||||
self.style = style
|
||||
|
||||
class CollectionNode(Node):
|
||||
def __init__(self, tag, value,
|
||||
start_mark=None, end_mark=None, flow_style=None):
|
||||
self.tag = tag
|
||||
self.value = value
|
||||
self.start_mark = start_mark
|
||||
self.end_mark = end_mark
|
||||
self.flow_style = flow_style
|
||||
|
||||
class SequenceNode(CollectionNode):
|
||||
id = 'sequence'
|
||||
|
||||
class MappingNode(CollectionNode):
|
||||
id = 'mapping'
|
||||
|
||||
@ -1,589 +0,0 @@
|
||||
|
||||
# The following YAML grammar is LL(1) and is parsed by a recursive descent
|
||||
# parser.
|
||||
#
|
||||
# stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
|
||||
# implicit_document ::= block_node DOCUMENT-END*
|
||||
# explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
|
||||
# block_node_or_indentless_sequence ::=
|
||||
# ALIAS
|
||||
# | properties (block_content | indentless_block_sequence)?
|
||||
# | block_content
|
||||
# | indentless_block_sequence
|
||||
# block_node ::= ALIAS
|
||||
# | properties block_content?
|
||||
# | block_content
|
||||
# flow_node ::= ALIAS
|
||||
# | properties flow_content?
|
||||
# | flow_content
|
||||
# properties ::= TAG ANCHOR? | ANCHOR TAG?
|
||||
# block_content ::= block_collection | flow_collection | SCALAR
|
||||
# flow_content ::= flow_collection | SCALAR
|
||||
# block_collection ::= block_sequence | block_mapping
|
||||
# flow_collection ::= flow_sequence | flow_mapping
|
||||
# block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
|
||||
# indentless_sequence ::= (BLOCK-ENTRY block_node?)+
|
||||
# block_mapping ::= BLOCK-MAPPING_START
|
||||
# ((KEY block_node_or_indentless_sequence?)?
|
||||
# (VALUE block_node_or_indentless_sequence?)?)*
|
||||
# BLOCK-END
|
||||
# flow_sequence ::= FLOW-SEQUENCE-START
|
||||
# (flow_sequence_entry FLOW-ENTRY)*
|
||||
# flow_sequence_entry?
|
||||
# FLOW-SEQUENCE-END
|
||||
# flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
|
||||
# flow_mapping ::= FLOW-MAPPING-START
|
||||
# (flow_mapping_entry FLOW-ENTRY)*
|
||||
# flow_mapping_entry?
|
||||
# FLOW-MAPPING-END
|
||||
# flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
|
||||
#
|
||||
# FIRST sets:
|
||||
#
|
||||
# stream: { STREAM-START }
|
||||
# explicit_document: { DIRECTIVE DOCUMENT-START }
|
||||
# implicit_document: FIRST(block_node)
|
||||
# block_node: { ALIAS TAG ANCHOR SCALAR BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START }
|
||||
# flow_node: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START }
|
||||
# block_content: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR }
|
||||
# flow_content: { FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR }
|
||||
# block_collection: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START }
|
||||
# flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START }
|
||||
# block_sequence: { BLOCK-SEQUENCE-START }
|
||||
# block_mapping: { BLOCK-MAPPING-START }
|
||||
# block_node_or_indentless_sequence: { ALIAS ANCHOR TAG SCALAR BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START BLOCK-ENTRY }
|
||||
# indentless_sequence: { ENTRY }
|
||||
# flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START }
|
||||
# flow_sequence: { FLOW-SEQUENCE-START }
|
||||
# flow_mapping: { FLOW-MAPPING-START }
|
||||
# flow_sequence_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START KEY }
|
||||
# flow_mapping_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START KEY }
|
||||
|
||||
__all__ = ['Parser', 'ParserError']
|
||||
|
||||
from .error import MarkedYAMLError
|
||||
from .tokens import *
|
||||
from .events import *
|
||||
from .scanner import *
|
||||
|
||||
class ParserError(MarkedYAMLError):
|
||||
pass
|
||||
|
||||
class Parser:
|
||||
# Since writing a recursive-descendant parser is a straightforward task, we
|
||||
# do not give many comments here.
|
||||
|
||||
DEFAULT_TAGS = {
|
||||
'!': '!',
|
||||
'!!': 'tag:yaml.org,2002:',
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
self.current_event = None
|
||||
self.yaml_version = None
|
||||
self.tag_handles = {}
|
||||
self.states = []
|
||||
self.marks = []
|
||||
self.state = self.parse_stream_start
|
||||
|
||||
def dispose(self):
|
||||
# Reset the state attributes (to clear self-references)
|
||||
self.states = []
|
||||
self.state = None
|
||||
|
||||
def check_event(self, *choices):
|
||||
# Check the type of the next event.
|
||||
if self.current_event is None:
|
||||
if self.state:
|
||||
self.current_event = self.state()
|
||||
if self.current_event is not None:
|
||||
if not choices:
|
||||
return True
|
||||
for choice in choices:
|
||||
if isinstance(self.current_event, choice):
|
||||
return True
|
||||
return False
|
||||
|
||||
def peek_event(self):
|
||||
# Get the next event.
|
||||
if self.current_event is None:
|
||||
if self.state:
|
||||
self.current_event = self.state()
|
||||
return self.current_event
|
||||
|
||||
def get_event(self):
|
||||
# Get the next event and proceed further.
|
||||
if self.current_event is None:
|
||||
if self.state:
|
||||
self.current_event = self.state()
|
||||
value = self.current_event
|
||||
self.current_event = None
|
||||
return value
|
||||
|
||||
# stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
|
||||
# implicit_document ::= block_node DOCUMENT-END*
|
||||
# explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
|
||||
|
||||
def parse_stream_start(self):
|
||||
|
||||
# Parse the stream start.
|
||||
token = self.get_token()
|
||||
event = StreamStartEvent(token.start_mark, token.end_mark,
|
||||
encoding=token.encoding)
|
||||
|
||||
# Prepare the next state.
|
||||
self.state = self.parse_implicit_document_start
|
||||
|
||||
return event
|
||||
|
||||
def parse_implicit_document_start(self):
|
||||
|
||||
# Parse an implicit document.
|
||||
if not self.check_token(DirectiveToken, DocumentStartToken,
|
||||
StreamEndToken):
|
||||
self.tag_handles = self.DEFAULT_TAGS
|
||||
token = self.peek_token()
|
||||
start_mark = end_mark = token.start_mark
|
||||
event = DocumentStartEvent(start_mark, end_mark,
|
||||
explicit=False)
|
||||
|
||||
# Prepare the next state.
|
||||
self.states.append(self.parse_document_end)
|
||||
self.state = self.parse_block_node
|
||||
|
||||
return event
|
||||
|
||||
else:
|
||||
return self.parse_document_start()
|
||||
|
||||
def parse_document_start(self):
|
||||
|
||||
# Parse any extra document end indicators.
|
||||
while self.check_token(DocumentEndToken):
|
||||
self.get_token()
|
||||
|
||||
# Parse an explicit document.
|
||||
if not self.check_token(StreamEndToken):
|
||||
token = self.peek_token()
|
||||
start_mark = token.start_mark
|
||||
version, tags = self.process_directives()
|
||||
if not self.check_token(DocumentStartToken):
|
||||
raise ParserError(None, None,
|
||||
"expected '<document start>', but found %r"
|
||||
% self.peek_token().id,
|
||||
self.peek_token().start_mark)
|
||||
token = self.get_token()
|
||||
end_mark = token.end_mark
|
||||
event = DocumentStartEvent(start_mark, end_mark,
|
||||
explicit=True, version=version, tags=tags)
|
||||
self.states.append(self.parse_document_end)
|
||||
self.state = self.parse_document_content
|
||||
else:
|
||||
# Parse the end of the stream.
|
||||
token = self.get_token()
|
||||
event = StreamEndEvent(token.start_mark, token.end_mark)
|
||||
assert not self.states
|
||||
assert not self.marks
|
||||
self.state = None
|
||||
return event
|
||||
|
||||
def parse_document_end(self):
|
||||
|
||||
# Parse the document end.
|
||||
token = self.peek_token()
|
||||
start_mark = end_mark = token.start_mark
|
||||
explicit = False
|
||||
if self.check_token(DocumentEndToken):
|
||||
token = self.get_token()
|
||||
end_mark = token.end_mark
|
||||
explicit = True
|
||||
event = DocumentEndEvent(start_mark, end_mark,
|
||||
explicit=explicit)
|
||||
|
||||
# Prepare the next state.
|
||||
self.state = self.parse_document_start
|
||||
|
||||
return event
|
||||
|
||||
def parse_document_content(self):
|
||||
if self.check_token(DirectiveToken,
|
||||
DocumentStartToken, DocumentEndToken, StreamEndToken):
|
||||
event = self.process_empty_scalar(self.peek_token().start_mark)
|
||||
self.state = self.states.pop()
|
||||
return event
|
||||
else:
|
||||
return self.parse_block_node()
|
||||
|
||||
def process_directives(self):
|
||||
self.yaml_version = None
|
||||
self.tag_handles = {}
|
||||
while self.check_token(DirectiveToken):
|
||||
token = self.get_token()
|
||||
if token.name == 'YAML':
|
||||
if self.yaml_version is not None:
|
||||
raise ParserError(None, None,
|
||||
"found duplicate YAML directive", token.start_mark)
|
||||
major, minor = token.value
|
||||
if major != 1:
|
||||
raise ParserError(None, None,
|
||||
"found incompatible YAML document (version 1.* is required)",
|
||||
token.start_mark)
|
||||
self.yaml_version = token.value
|
||||
elif token.name == 'TAG':
|
||||
handle, prefix = token.value
|
||||
if handle in self.tag_handles:
|
||||
raise ParserError(None, None,
|
||||
"duplicate tag handle %r" % handle,
|
||||
token.start_mark)
|
||||
self.tag_handles[handle] = prefix
|
||||
if self.tag_handles:
|
||||
value = self.yaml_version, self.tag_handles.copy()
|
||||
else:
|
||||
value = self.yaml_version, None
|
||||
for key in self.DEFAULT_TAGS:
|
||||
if key not in self.tag_handles:
|
||||
self.tag_handles[key] = self.DEFAULT_TAGS[key]
|
||||
return value
|
||||
|
||||
# block_node_or_indentless_sequence ::= ALIAS
|
||||
# | properties (block_content | indentless_block_sequence)?
|
||||
# | block_content
|
||||
# | indentless_block_sequence
|
||||
# block_node ::= ALIAS
|
||||
# | properties block_content?
|
||||
# | block_content
|
||||
# flow_node ::= ALIAS
|
||||
# | properties flow_content?
|
||||
# | flow_content
|
||||
# properties ::= TAG ANCHOR? | ANCHOR TAG?
|
||||
# block_content ::= block_collection | flow_collection | SCALAR
|
||||
# flow_content ::= flow_collection | SCALAR
|
||||
# block_collection ::= block_sequence | block_mapping
|
||||
# flow_collection ::= flow_sequence | flow_mapping
|
||||
|
||||
def parse_block_node(self):
|
||||
return self.parse_node(block=True)
|
||||
|
||||
def parse_flow_node(self):
|
||||
return self.parse_node()
|
||||
|
||||
def parse_block_node_or_indentless_sequence(self):
|
||||
return self.parse_node(block=True, indentless_sequence=True)
|
||||
|
||||
def parse_node(self, block=False, indentless_sequence=False):
|
||||
if self.check_token(AliasToken):
|
||||
token = self.get_token()
|
||||
event = AliasEvent(token.value, token.start_mark, token.end_mark)
|
||||
self.state = self.states.pop()
|
||||
else:
|
||||
anchor = None
|
||||
tag = None
|
||||
start_mark = end_mark = tag_mark = None
|
||||
if self.check_token(AnchorToken):
|
||||
token = self.get_token()
|
||||
start_mark = token.start_mark
|
||||
end_mark = token.end_mark
|
||||
anchor = token.value
|
||||
if self.check_token(TagToken):
|
||||
token = self.get_token()
|
||||
tag_mark = token.start_mark
|
||||
end_mark = token.end_mark
|
||||
tag = token.value
|
||||
elif self.check_token(TagToken):
|
||||
token = self.get_token()
|
||||
start_mark = tag_mark = token.start_mark
|
||||
end_mark = token.end_mark
|
||||
tag = token.value
|
||||
if self.check_token(AnchorToken):
|
||||
token = self.get_token()
|
||||
end_mark = token.end_mark
|
||||
anchor = token.value
|
||||
if tag is not None:
|
||||
handle, suffix = tag
|
||||
if handle is not None:
|
||||
if handle not in self.tag_handles:
|
||||
raise ParserError("while parsing a node", start_mark,
|
||||
"found undefined tag handle %r" % handle,
|
||||
tag_mark)
|
||||
tag = self.tag_handles[handle]+suffix
|
||||
else:
|
||||
tag = suffix
|
||||
#if tag == '!':
|
||||
# raise ParserError("while parsing a node", start_mark,
|
||||
# "found non-specific tag '!'", tag_mark,
|
||||
# "Please check 'http://pyyaml.org/wiki/YAMLNonSpecificTag' and share your opinion.")
|
||||
if start_mark is None:
|
||||
start_mark = end_mark = self.peek_token().start_mark
|
||||
event = None
|
||||
implicit = (tag is None or tag == '!')
|
||||
if indentless_sequence and self.check_token(BlockEntryToken):
|
||||
end_mark = self.peek_token().end_mark
|
||||
event = SequenceStartEvent(anchor, tag, implicit,
|
||||
start_mark, end_mark)
|
||||
self.state = self.parse_indentless_sequence_entry
|
||||
else:
|
||||
if self.check_token(ScalarToken):
|
||||
token = self.get_token()
|
||||
end_mark = token.end_mark
|
||||
if (token.plain and tag is None) or tag == '!':
|
||||
implicit = (True, False)
|
||||
elif tag is None:
|
||||
implicit = (False, True)
|
||||
else:
|
||||
implicit = (False, False)
|
||||
event = ScalarEvent(anchor, tag, implicit, token.value,
|
||||
start_mark, end_mark, style=token.style)
|
||||
self.state = self.states.pop()
|
||||
elif self.check_token(FlowSequenceStartToken):
|
||||
end_mark = self.peek_token().end_mark
|
||||
event = SequenceStartEvent(anchor, tag, implicit,
|
||||
start_mark, end_mark, flow_style=True)
|
||||
self.state = self.parse_flow_sequence_first_entry
|
||||
elif self.check_token(FlowMappingStartToken):
|
||||
end_mark = self.peek_token().end_mark
|
||||
event = MappingStartEvent(anchor, tag, implicit,
|
||||
start_mark, end_mark, flow_style=True)
|
||||
self.state = self.parse_flow_mapping_first_key
|
||||
elif block and self.check_token(BlockSequenceStartToken):
|
||||
end_mark = self.peek_token().start_mark
|
||||
event = SequenceStartEvent(anchor, tag, implicit,
|
||||
start_mark, end_mark, flow_style=False)
|
||||
self.state = self.parse_block_sequence_first_entry
|
||||
elif block and self.check_token(BlockMappingStartToken):
|
||||
end_mark = self.peek_token().start_mark
|
||||
event = MappingStartEvent(anchor, tag, implicit,
|
||||
start_mark, end_mark, flow_style=False)
|
||||
self.state = self.parse_block_mapping_first_key
|
||||
elif anchor is not None or tag is not None:
|
||||
# Empty scalars are allowed even if a tag or an anchor is
|
||||
# specified.
|
||||
event = ScalarEvent(anchor, tag, (implicit, False), '',
|
||||
start_mark, end_mark)
|
||||
self.state = self.states.pop()
|
||||
else:
|
||||
if block:
|
||||
node = 'block'
|
||||
else:
|
||||
node = 'flow'
|
||||
token = self.peek_token()
|
||||
raise ParserError("while parsing a %s node" % node, start_mark,
|
||||
"expected the node content, but found %r" % token.id,
|
||||
token.start_mark)
|
||||
return event
|
||||
|
||||
# block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
|
||||
|
||||
def parse_block_sequence_first_entry(self):
|
||||
token = self.get_token()
|
||||
self.marks.append(token.start_mark)
|
||||
return self.parse_block_sequence_entry()
|
||||
|
||||
def parse_block_sequence_entry(self):
|
||||
if self.check_token(BlockEntryToken):
|
||||
token = self.get_token()
|
||||
if not self.check_token(BlockEntryToken, BlockEndToken):
|
||||
self.states.append(self.parse_block_sequence_entry)
|
||||
return self.parse_block_node()
|
||||
else:
|
||||
self.state = self.parse_block_sequence_entry
|
||||
return self.process_empty_scalar(token.end_mark)
|
||||
if not self.check_token(BlockEndToken):
|
||||
token = self.peek_token()
|
||||
raise ParserError("while parsing a block collection", self.marks[-1],
|
||||
"expected <block end>, but found %r" % token.id, token.start_mark)
|
||||
token = self.get_token()
|
||||
event = SequenceEndEvent(token.start_mark, token.end_mark)
|
||||
self.state = self.states.pop()
|
||||
self.marks.pop()
|
||||
return event
|
||||
|
||||
# indentless_sequence ::= (BLOCK-ENTRY block_node?)+
|
||||
|
||||
def parse_indentless_sequence_entry(self):
|
||||
if self.check_token(BlockEntryToken):
|
||||
token = self.get_token()
|
||||
if not self.check_token(BlockEntryToken,
|
||||
KeyToken, ValueToken, BlockEndToken):
|
||||
self.states.append(self.parse_indentless_sequence_entry)
|
||||
return self.parse_block_node()
|
||||
else:
|
||||
self.state = self.parse_indentless_sequence_entry
|
||||
return self.process_empty_scalar(token.end_mark)
|
||||
token = self.peek_token()
|
||||
event = SequenceEndEvent(token.start_mark, token.start_mark)
|
||||
self.state = self.states.pop()
|
||||
return event
|
||||
|
||||
# block_mapping ::= BLOCK-MAPPING_START
|
||||
# ((KEY block_node_or_indentless_sequence?)?
|
||||
# (VALUE block_node_or_indentless_sequence?)?)*
|
||||
# BLOCK-END
|
||||
|
||||
def parse_block_mapping_first_key(self):
|
||||
token = self.get_token()
|
||||
self.marks.append(token.start_mark)
|
||||
return self.parse_block_mapping_key()
|
||||
|
||||
def parse_block_mapping_key(self):
|
||||
if self.check_token(KeyToken):
|
||||
token = self.get_token()
|
||||
if not self.check_token(KeyToken, ValueToken, BlockEndToken):
|
||||
self.states.append(self.parse_block_mapping_value)
|
||||
return self.parse_block_node_or_indentless_sequence()
|
||||
else:
|
||||
self.state = self.parse_block_mapping_value
|
||||
return self.process_empty_scalar(token.end_mark)
|
||||
if not self.check_token(BlockEndToken):
|
||||
token = self.peek_token()
|
||||
raise ParserError("while parsing a block mapping", self.marks[-1],
|
||||
"expected <block end>, but found %r" % token.id, token.start_mark)
|
||||
token = self.get_token()
|
||||
event = MappingEndEvent(token.start_mark, token.end_mark)
|
||||
self.state = self.states.pop()
|
||||
self.marks.pop()
|
||||
return event
|
||||
|
||||
def parse_block_mapping_value(self):
|
||||
if self.check_token(ValueToken):
|
||||
token = self.get_token()
|
||||
if not self.check_token(KeyToken, ValueToken, BlockEndToken):
|
||||
self.states.append(self.parse_block_mapping_key)
|
||||
return self.parse_block_node_or_indentless_sequence()
|
||||
else:
|
||||
self.state = self.parse_block_mapping_key
|
||||
return self.process_empty_scalar(token.end_mark)
|
||||
else:
|
||||
self.state = self.parse_block_mapping_key
|
||||
token = self.peek_token()
|
||||
return self.process_empty_scalar(token.start_mark)
|
||||
|
||||
# flow_sequence ::= FLOW-SEQUENCE-START
|
||||
# (flow_sequence_entry FLOW-ENTRY)*
|
||||
# flow_sequence_entry?
|
||||
# FLOW-SEQUENCE-END
|
||||
# flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
|
||||
#
|
||||
# Note that while production rules for both flow_sequence_entry and
|
||||
# flow_mapping_entry are equal, their interpretations are different.
|
||||
# For `flow_sequence_entry`, the part `KEY flow_node? (VALUE flow_node?)?`
|
||||
# generate an inline mapping (set syntax).
|
||||
|
||||
def parse_flow_sequence_first_entry(self):
|
||||
token = self.get_token()
|
||||
self.marks.append(token.start_mark)
|
||||
return self.parse_flow_sequence_entry(first=True)
|
||||
|
||||
def parse_flow_sequence_entry(self, first=False):
|
||||
if not self.check_token(FlowSequenceEndToken):
|
||||
if not first:
|
||||
if self.check_token(FlowEntryToken):
|
||||
self.get_token()
|
||||
else:
|
||||
token = self.peek_token()
|
||||
raise ParserError("while parsing a flow sequence", self.marks[-1],
|
||||
"expected ',' or ']', but got %r" % token.id, token.start_mark)
|
||||
|
||||
if self.check_token(KeyToken):
|
||||
token = self.peek_token()
|
||||
event = MappingStartEvent(None, None, True,
|
||||
token.start_mark, token.end_mark,
|
||||
flow_style=True)
|
||||
self.state = self.parse_flow_sequence_entry_mapping_key
|
||||
return event
|
||||
elif not self.check_token(FlowSequenceEndToken):
|
||||
self.states.append(self.parse_flow_sequence_entry)
|
||||
return self.parse_flow_node()
|
||||
token = self.get_token()
|
||||
event = SequenceEndEvent(token.start_mark, token.end_mark)
|
||||
self.state = self.states.pop()
|
||||
self.marks.pop()
|
||||
return event
|
||||
|
||||
def parse_flow_sequence_entry_mapping_key(self):
|
||||
token = self.get_token()
|
||||
if not self.check_token(ValueToken,
|
||||
FlowEntryToken, FlowSequenceEndToken):
|
||||
self.states.append(self.parse_flow_sequence_entry_mapping_value)
|
||||
return self.parse_flow_node()
|
||||
else:
|
||||
self.state = self.parse_flow_sequence_entry_mapping_value
|
||||
return self.process_empty_scalar(token.end_mark)
|
||||
|
||||
def parse_flow_sequence_entry_mapping_value(self):
|
||||
if self.check_token(ValueToken):
|
||||
token = self.get_token()
|
||||
if not self.check_token(FlowEntryToken, FlowSequenceEndToken):
|
||||
self.states.append(self.parse_flow_sequence_entry_mapping_end)
|
||||
return self.parse_flow_node()
|
||||
else:
|
||||
self.state = self.parse_flow_sequence_entry_mapping_end
|
||||
return self.process_empty_scalar(token.end_mark)
|
||||
else:
|
||||
self.state = self.parse_flow_sequence_entry_mapping_end
|
||||
token = self.peek_token()
|
||||
return self.process_empty_scalar(token.start_mark)
|
||||
|
||||
def parse_flow_sequence_entry_mapping_end(self):
|
||||
self.state = self.parse_flow_sequence_entry
|
||||
token = self.peek_token()
|
||||
return MappingEndEvent(token.start_mark, token.start_mark)
|
||||
|
||||
# flow_mapping ::= FLOW-MAPPING-START
|
||||
# (flow_mapping_entry FLOW-ENTRY)*
|
||||
# flow_mapping_entry?
|
||||
# FLOW-MAPPING-END
|
||||
# flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
|
||||
|
||||
def parse_flow_mapping_first_key(self):
|
||||
token = self.get_token()
|
||||
self.marks.append(token.start_mark)
|
||||
return self.parse_flow_mapping_key(first=True)
|
||||
|
||||
def parse_flow_mapping_key(self, first=False):
|
||||
if not self.check_token(FlowMappingEndToken):
|
||||
if not first:
|
||||
if self.check_token(FlowEntryToken):
|
||||
self.get_token()
|
||||
else:
|
||||
token = self.peek_token()
|
||||
raise ParserError("while parsing a flow mapping", self.marks[-1],
|
||||
"expected ',' or '}', but got %r" % token.id, token.start_mark)
|
||||
if self.check_token(KeyToken):
|
||||
token = self.get_token()
|
||||
if not self.check_token(ValueToken,
|
||||
FlowEntryToken, FlowMappingEndToken):
|
||||
self.states.append(self.parse_flow_mapping_value)
|
||||
return self.parse_flow_node()
|
||||
else:
|
||||
self.state = self.parse_flow_mapping_value
|
||||
return self.process_empty_scalar(token.end_mark)
|
||||
elif not self.check_token(FlowMappingEndToken):
|
||||
self.states.append(self.parse_flow_mapping_empty_value)
|
||||
return self.parse_flow_node()
|
||||
token = self.get_token()
|
||||
event = MappingEndEvent(token.start_mark, token.end_mark)
|
||||
self.state = self.states.pop()
|
||||
self.marks.pop()
|
||||
return event
|
||||
|
||||
def parse_flow_mapping_value(self):
|
||||
if self.check_token(ValueToken):
|
||||
token = self.get_token()
|
||||
if not self.check_token(FlowEntryToken, FlowMappingEndToken):
|
||||
self.states.append(self.parse_flow_mapping_key)
|
||||
return self.parse_flow_node()
|
||||
else:
|
||||
self.state = self.parse_flow_mapping_key
|
||||
return self.process_empty_scalar(token.end_mark)
|
||||
else:
|
||||
self.state = self.parse_flow_mapping_key
|
||||
token = self.peek_token()
|
||||
return self.process_empty_scalar(token.start_mark)
|
||||
|
||||
def parse_flow_mapping_empty_value(self):
|
||||
self.state = self.parse_flow_mapping_key
|
||||
return self.process_empty_scalar(self.peek_token().start_mark)
|
||||
|
||||
def process_empty_scalar(self, mark):
|
||||
return ScalarEvent(None, None, (True, False), '', mark, mark)
|
||||
|
||||
@ -1,185 +0,0 @@
|
||||
# This module contains abstractions for the input stream. You don't have to
|
||||
# looks further, there are no pretty code.
|
||||
#
|
||||
# We define two classes here.
|
||||
#
|
||||
# Mark(source, line, column)
|
||||
# It's just a record and its only use is producing nice error messages.
|
||||
# Parser does not use it for any other purposes.
|
||||
#
|
||||
# Reader(source, data)
|
||||
# Reader determines the encoding of `data` and converts it to unicode.
|
||||
# Reader provides the following methods and attributes:
|
||||
# reader.peek(length=1) - return the next `length` characters
|
||||
# reader.forward(length=1) - move the current position to `length` characters.
|
||||
# reader.index - the number of the current character.
|
||||
# reader.line, stream.column - the line and the column of the current character.
|
||||
|
||||
__all__ = ['Reader', 'ReaderError']
|
||||
|
||||
from .error import YAMLError, Mark
|
||||
|
||||
import codecs, re
|
||||
|
||||
class ReaderError(YAMLError):
|
||||
|
||||
def __init__(self, name, position, character, encoding, reason):
|
||||
self.name = name
|
||||
self.character = character
|
||||
self.position = position
|
||||
self.encoding = encoding
|
||||
self.reason = reason
|
||||
|
||||
def __str__(self):
|
||||
if isinstance(self.character, bytes):
|
||||
return "'%s' codec can't decode byte #x%02x: %s\n" \
|
||||
" in \"%s\", position %d" \
|
||||
% (self.encoding, ord(self.character), self.reason,
|
||||
self.name, self.position)
|
||||
else:
|
||||
return "unacceptable character #x%04x: %s\n" \
|
||||
" in \"%s\", position %d" \
|
||||
% (self.character, self.reason,
|
||||
self.name, self.position)
|
||||
|
||||
class Reader(object):
|
||||
# Reader:
|
||||
# - determines the data encoding and converts it to a unicode string,
|
||||
# - checks if characters are in allowed range,
|
||||
# - adds '\0' to the end.
|
||||
|
||||
# Reader accepts
|
||||
# - a `bytes` object,
|
||||
# - a `str` object,
|
||||
# - a file-like object with its `read` method returning `str`,
|
||||
# - a file-like object with its `read` method returning `unicode`.
|
||||
|
||||
# Yeah, it's ugly and slow.
|
||||
|
||||
def __init__(self, stream):
|
||||
self.name = None
|
||||
self.stream = None
|
||||
self.stream_pointer = 0
|
||||
self.eof = True
|
||||
self.buffer = ''
|
||||
self.pointer = 0
|
||||
self.raw_buffer = None
|
||||
self.raw_decode = None
|
||||
self.encoding = None
|
||||
self.index = 0
|
||||
self.line = 0
|
||||
self.column = 0
|
||||
if isinstance(stream, str):
|
||||
self.name = "<unicode string>"
|
||||
self.check_printable(stream)
|
||||
self.buffer = stream+'\0'
|
||||
elif isinstance(stream, bytes):
|
||||
self.name = "<byte string>"
|
||||
self.raw_buffer = stream
|
||||
self.determine_encoding()
|
||||
else:
|
||||
self.stream = stream
|
||||
self.name = getattr(stream, 'name', "<file>")
|
||||
self.eof = False
|
||||
self.raw_buffer = None
|
||||
self.determine_encoding()
|
||||
|
||||
def peek(self, index=0):
|
||||
try:
|
||||
return self.buffer[self.pointer+index]
|
||||
except IndexError:
|
||||
self.update(index+1)
|
||||
return self.buffer[self.pointer+index]
|
||||
|
||||
def prefix(self, length=1):
|
||||
if self.pointer+length >= len(self.buffer):
|
||||
self.update(length)
|
||||
return self.buffer[self.pointer:self.pointer+length]
|
||||
|
||||
def forward(self, length=1):
|
||||
if self.pointer+length+1 >= len(self.buffer):
|
||||
self.update(length+1)
|
||||
while length:
|
||||
ch = self.buffer[self.pointer]
|
||||
self.pointer += 1
|
||||
self.index += 1
|
||||
if ch in '\n\x85\u2028\u2029' \
|
||||
or (ch == '\r' and self.buffer[self.pointer] != '\n'):
|
||||
self.line += 1
|
||||
self.column = 0
|
||||
elif ch != '\uFEFF':
|
||||
self.column += 1
|
||||
length -= 1
|
||||
|
||||
def get_mark(self):
|
||||
if self.stream is None:
|
||||
return Mark(self.name, self.index, self.line, self.column,
|
||||
self.buffer, self.pointer)
|
||||
else:
|
||||
return Mark(self.name, self.index, self.line, self.column,
|
||||
None, None)
|
||||
|
||||
def determine_encoding(self):
|
||||
while not self.eof and (self.raw_buffer is None or len(self.raw_buffer) < 2):
|
||||
self.update_raw()
|
||||
if isinstance(self.raw_buffer, bytes):
|
||||
if self.raw_buffer.startswith(codecs.BOM_UTF16_LE):
|
||||
self.raw_decode = codecs.utf_16_le_decode
|
||||
self.encoding = 'utf-16-le'
|
||||
elif self.raw_buffer.startswith(codecs.BOM_UTF16_BE):
|
||||
self.raw_decode = codecs.utf_16_be_decode
|
||||
self.encoding = 'utf-16-be'
|
||||
else:
|
||||
self.raw_decode = codecs.utf_8_decode
|
||||
self.encoding = 'utf-8'
|
||||
self.update(1)
|
||||
|
||||
NON_PRINTABLE = re.compile('[^\x09\x0A\x0D\x20-\x7E\x85\xA0-\uD7FF\uE000-\uFFFD\U00010000-\U0010ffff]')
|
||||
def check_printable(self, data):
|
||||
match = self.NON_PRINTABLE.search(data)
|
||||
if match:
|
||||
character = match.group()
|
||||
position = self.index+(len(self.buffer)-self.pointer)+match.start()
|
||||
raise ReaderError(self.name, position, ord(character),
|
||||
'unicode', "special characters are not allowed")
|
||||
|
||||
def update(self, length):
|
||||
if self.raw_buffer is None:
|
||||
return
|
||||
self.buffer = self.buffer[self.pointer:]
|
||||
self.pointer = 0
|
||||
while len(self.buffer) < length:
|
||||
if not self.eof:
|
||||
self.update_raw()
|
||||
if self.raw_decode is not None:
|
||||
try:
|
||||
data, converted = self.raw_decode(self.raw_buffer,
|
||||
'strict', self.eof)
|
||||
except UnicodeDecodeError as exc:
|
||||
character = self.raw_buffer[exc.start]
|
||||
if self.stream is not None:
|
||||
position = self.stream_pointer-len(self.raw_buffer)+exc.start
|
||||
else:
|
||||
position = exc.start
|
||||
raise ReaderError(self.name, position, character,
|
||||
exc.encoding, exc.reason)
|
||||
else:
|
||||
data = self.raw_buffer
|
||||
converted = len(data)
|
||||
self.check_printable(data)
|
||||
self.buffer += data
|
||||
self.raw_buffer = self.raw_buffer[converted:]
|
||||
if self.eof:
|
||||
self.buffer += '\0'
|
||||
self.raw_buffer = None
|
||||
break
|
||||
|
||||
def update_raw(self, size=4096):
|
||||
data = self.stream.read(size)
|
||||
if self.raw_buffer is None:
|
||||
self.raw_buffer = data
|
||||
else:
|
||||
self.raw_buffer += data
|
||||
self.stream_pointer += len(data)
|
||||
if not data:
|
||||
self.eof = True
|
||||
@ -1,389 +0,0 @@
|
||||
|
||||
__all__ = ['BaseRepresenter', 'SafeRepresenter', 'Representer',
|
||||
'RepresenterError']
|
||||
|
||||
from .error import *
|
||||
from .nodes import *
|
||||
|
||||
import datetime, copyreg, types, base64, collections
|
||||
|
||||
class RepresenterError(YAMLError):
|
||||
pass
|
||||
|
||||
class BaseRepresenter:
|
||||
|
||||
yaml_representers = {}
|
||||
yaml_multi_representers = {}
|
||||
|
||||
def __init__(self, default_style=None, default_flow_style=False, sort_keys=True):
|
||||
self.default_style = default_style
|
||||
self.sort_keys = sort_keys
|
||||
self.default_flow_style = default_flow_style
|
||||
self.represented_objects = {}
|
||||
self.object_keeper = []
|
||||
self.alias_key = None
|
||||
|
||||
def represent(self, data):
|
||||
node = self.represent_data(data)
|
||||
self.serialize(node)
|
||||
self.represented_objects = {}
|
||||
self.object_keeper = []
|
||||
self.alias_key = None
|
||||
|
||||
def represent_data(self, data):
|
||||
if self.ignore_aliases(data):
|
||||
self.alias_key = None
|
||||
else:
|
||||
self.alias_key = id(data)
|
||||
if self.alias_key is not None:
|
||||
if self.alias_key in self.represented_objects:
|
||||
node = self.represented_objects[self.alias_key]
|
||||
#if node is None:
|
||||
# raise RepresenterError("recursive objects are not allowed: %r" % data)
|
||||
return node
|
||||
#self.represented_objects[alias_key] = None
|
||||
self.object_keeper.append(data)
|
||||
data_types = type(data).__mro__
|
||||
if data_types[0] in self.yaml_representers:
|
||||
node = self.yaml_representers[data_types[0]](self, data)
|
||||
else:
|
||||
for data_type in data_types:
|
||||
if data_type in self.yaml_multi_representers:
|
||||
node = self.yaml_multi_representers[data_type](self, data)
|
||||
break
|
||||
else:
|
||||
if None in self.yaml_multi_representers:
|
||||
node = self.yaml_multi_representers[None](self, data)
|
||||
elif None in self.yaml_representers:
|
||||
node = self.yaml_representers[None](self, data)
|
||||
else:
|
||||
node = ScalarNode(None, str(data))
|
||||
#if alias_key is not None:
|
||||
# self.represented_objects[alias_key] = node
|
||||
return node
|
||||
|
||||
@classmethod
|
||||
def add_representer(cls, data_type, representer):
|
||||
if not 'yaml_representers' in cls.__dict__:
|
||||
cls.yaml_representers = cls.yaml_representers.copy()
|
||||
cls.yaml_representers[data_type] = representer
|
||||
|
||||
@classmethod
|
||||
def add_multi_representer(cls, data_type, representer):
|
||||
if not 'yaml_multi_representers' in cls.__dict__:
|
||||
cls.yaml_multi_representers = cls.yaml_multi_representers.copy()
|
||||
cls.yaml_multi_representers[data_type] = representer
|
||||
|
||||
def represent_scalar(self, tag, value, style=None):
|
||||
if style is None:
|
||||
style = self.default_style
|
||||
node = ScalarNode(tag, value, style=style)
|
||||
if self.alias_key is not None:
|
||||
self.represented_objects[self.alias_key] = node
|
||||
return node
|
||||
|
||||
def represent_sequence(self, tag, sequence, flow_style=None):
|
||||
value = []
|
||||
node = SequenceNode(tag, value, flow_style=flow_style)
|
||||
if self.alias_key is not None:
|
||||
self.represented_objects[self.alias_key] = node
|
||||
best_style = True
|
||||
for item in sequence:
|
||||
node_item = self.represent_data(item)
|
||||
if not (isinstance(node_item, ScalarNode) and not node_item.style):
|
||||
best_style = False
|
||||
value.append(node_item)
|
||||
if flow_style is None:
|
||||
if self.default_flow_style is not None:
|
||||
node.flow_style = self.default_flow_style
|
||||
else:
|
||||
node.flow_style = best_style
|
||||
return node
|
||||
|
||||
def represent_mapping(self, tag, mapping, flow_style=None):
|
||||
value = []
|
||||
node = MappingNode(tag, value, flow_style=flow_style)
|
||||
if self.alias_key is not None:
|
||||
self.represented_objects[self.alias_key] = node
|
||||
best_style = True
|
||||
if hasattr(mapping, 'items'):
|
||||
mapping = list(mapping.items())
|
||||
if self.sort_keys:
|
||||
try:
|
||||
mapping = sorted(mapping)
|
||||
except TypeError:
|
||||
pass
|
||||
for item_key, item_value in mapping:
|
||||
node_key = self.represent_data(item_key)
|
||||
node_value = self.represent_data(item_value)
|
||||
if not (isinstance(node_key, ScalarNode) and not node_key.style):
|
||||
best_style = False
|
||||
if not (isinstance(node_value, ScalarNode) and not node_value.style):
|
||||
best_style = False
|
||||
value.append((node_key, node_value))
|
||||
if flow_style is None:
|
||||
if self.default_flow_style is not None:
|
||||
node.flow_style = self.default_flow_style
|
||||
else:
|
||||
node.flow_style = best_style
|
||||
return node
|
||||
|
||||
def ignore_aliases(self, data):
|
||||
return False
|
||||
|
||||
class SafeRepresenter(BaseRepresenter):
|
||||
|
||||
def ignore_aliases(self, data):
|
||||
if data is None:
|
||||
return True
|
||||
if isinstance(data, tuple) and data == ():
|
||||
return True
|
||||
if isinstance(data, (str, bytes, bool, int, float)):
|
||||
return True
|
||||
|
||||
def represent_none(self, data):
|
||||
return self.represent_scalar('tag:yaml.org,2002:null', 'null')
|
||||
|
||||
def represent_str(self, data):
|
||||
return self.represent_scalar('tag:yaml.org,2002:str', data)
|
||||
|
||||
def represent_binary(self, data):
|
||||
if hasattr(base64, 'encodebytes'):
|
||||
data = base64.encodebytes(data).decode('ascii')
|
||||
else:
|
||||
data = base64.encodestring(data).decode('ascii')
|
||||
return self.represent_scalar('tag:yaml.org,2002:binary', data, style='|')
|
||||
|
||||
def represent_bool(self, data):
|
||||
if data:
|
||||
value = 'true'
|
||||
else:
|
||||
value = 'false'
|
||||
return self.represent_scalar('tag:yaml.org,2002:bool', value)
|
||||
|
||||
def represent_int(self, data):
|
||||
return self.represent_scalar('tag:yaml.org,2002:int', str(data))
|
||||
|
||||
inf_value = 1e300
|
||||
while repr(inf_value) != repr(inf_value*inf_value):
|
||||
inf_value *= inf_value
|
||||
|
||||
def represent_float(self, data):
|
||||
if data != data or (data == 0.0 and data == 1.0):
|
||||
value = '.nan'
|
||||
elif data == self.inf_value:
|
||||
value = '.inf'
|
||||
elif data == -self.inf_value:
|
||||
value = '-.inf'
|
||||
else:
|
||||
value = repr(data).lower()
|
||||
# Note that in some cases `repr(data)` represents a float number
|
||||
# without the decimal parts. For instance:
|
||||
# >>> repr(1e17)
|
||||
# '1e17'
|
||||
# Unfortunately, this is not a valid float representation according
|
||||
# to the definition of the `!!float` tag. We fix this by adding
|
||||
# '.0' before the 'e' symbol.
|
||||
if '.' not in value and 'e' in value:
|
||||
value = value.replace('e', '.0e', 1)
|
||||
return self.represent_scalar('tag:yaml.org,2002:float', value)
|
||||
|
||||
def represent_list(self, data):
|
||||
#pairs = (len(data) > 0 and isinstance(data, list))
|
||||
#if pairs:
|
||||
# for item in data:
|
||||
# if not isinstance(item, tuple) or len(item) != 2:
|
||||
# pairs = False
|
||||
# break
|
||||
#if not pairs:
|
||||
return self.represent_sequence('tag:yaml.org,2002:seq', data)
|
||||
#value = []
|
||||
#for item_key, item_value in data:
|
||||
# value.append(self.represent_mapping(u'tag:yaml.org,2002:map',
|
||||
# [(item_key, item_value)]))
|
||||
#return SequenceNode(u'tag:yaml.org,2002:pairs', value)
|
||||
|
||||
def represent_dict(self, data):
|
||||
return self.represent_mapping('tag:yaml.org,2002:map', data)
|
||||
|
||||
def represent_set(self, data):
|
||||
value = {}
|
||||
for key in data:
|
||||
value[key] = None
|
||||
return self.represent_mapping('tag:yaml.org,2002:set', value)
|
||||
|
||||
def represent_date(self, data):
|
||||
value = data.isoformat()
|
||||
return self.represent_scalar('tag:yaml.org,2002:timestamp', value)
|
||||
|
||||
def represent_datetime(self, data):
|
||||
value = data.isoformat(' ')
|
||||
return self.represent_scalar('tag:yaml.org,2002:timestamp', value)
|
||||
|
||||
def represent_yaml_object(self, tag, data, cls, flow_style=None):
|
||||
if hasattr(data, '__getstate__'):
|
||||
state = data.__getstate__()
|
||||
else:
|
||||
state = data.__dict__.copy()
|
||||
return self.represent_mapping(tag, state, flow_style=flow_style)
|
||||
|
||||
def represent_undefined(self, data):
|
||||
raise RepresenterError("cannot represent an object", data)
|
||||
|
||||
SafeRepresenter.add_representer(type(None),
|
||||
SafeRepresenter.represent_none)
|
||||
|
||||
SafeRepresenter.add_representer(str,
|
||||
SafeRepresenter.represent_str)
|
||||
|
||||
SafeRepresenter.add_representer(bytes,
|
||||
SafeRepresenter.represent_binary)
|
||||
|
||||
SafeRepresenter.add_representer(bool,
|
||||
SafeRepresenter.represent_bool)
|
||||
|
||||
SafeRepresenter.add_representer(int,
|
||||
SafeRepresenter.represent_int)
|
||||
|
||||
SafeRepresenter.add_representer(float,
|
||||
SafeRepresenter.represent_float)
|
||||
|
||||
SafeRepresenter.add_representer(list,
|
||||
SafeRepresenter.represent_list)
|
||||
|
||||
SafeRepresenter.add_representer(tuple,
|
||||
SafeRepresenter.represent_list)
|
||||
|
||||
SafeRepresenter.add_representer(dict,
|
||||
SafeRepresenter.represent_dict)
|
||||
|
||||
SafeRepresenter.add_representer(set,
|
||||
SafeRepresenter.represent_set)
|
||||
|
||||
SafeRepresenter.add_representer(datetime.date,
|
||||
SafeRepresenter.represent_date)
|
||||
|
||||
SafeRepresenter.add_representer(datetime.datetime,
|
||||
SafeRepresenter.represent_datetime)
|
||||
|
||||
SafeRepresenter.add_representer(None,
|
||||
SafeRepresenter.represent_undefined)
|
||||
|
||||
class Representer(SafeRepresenter):
|
||||
|
||||
def represent_complex(self, data):
|
||||
if data.imag == 0.0:
|
||||
data = '%r' % data.real
|
||||
elif data.real == 0.0:
|
||||
data = '%rj' % data.imag
|
||||
elif data.imag > 0:
|
||||
data = '%r+%rj' % (data.real, data.imag)
|
||||
else:
|
||||
data = '%r%rj' % (data.real, data.imag)
|
||||
return self.represent_scalar('tag:yaml.org,2002:python/complex', data)
|
||||
|
||||
def represent_tuple(self, data):
|
||||
return self.represent_sequence('tag:yaml.org,2002:python/tuple', data)
|
||||
|
||||
def represent_name(self, data):
|
||||
name = '%s.%s' % (data.__module__, data.__name__)
|
||||
return self.represent_scalar('tag:yaml.org,2002:python/name:'+name, '')
|
||||
|
||||
def represent_module(self, data):
|
||||
return self.represent_scalar(
|
||||
'tag:yaml.org,2002:python/module:'+data.__name__, '')
|
||||
|
||||
def represent_object(self, data):
|
||||
# We use __reduce__ API to save the data. data.__reduce__ returns
|
||||
# a tuple of length 2-5:
|
||||
# (function, args, state, listitems, dictitems)
|
||||
|
||||
# For reconstructing, we calls function(*args), then set its state,
|
||||
# listitems, and dictitems if they are not None.
|
||||
|
||||
# A special case is when function.__name__ == '__newobj__'. In this
|
||||
# case we create the object with args[0].__new__(*args).
|
||||
|
||||
# Another special case is when __reduce__ returns a string - we don't
|
||||
# support it.
|
||||
|
||||
# We produce a !!python/object, !!python/object/new or
|
||||
# !!python/object/apply node.
|
||||
|
||||
cls = type(data)
|
||||
if cls in copyreg.dispatch_table:
|
||||
reduce = copyreg.dispatch_table[cls](data)
|
||||
elif hasattr(data, '__reduce_ex__'):
|
||||
reduce = data.__reduce_ex__(2)
|
||||
elif hasattr(data, '__reduce__'):
|
||||
reduce = data.__reduce__()
|
||||
else:
|
||||
raise RepresenterError("cannot represent an object", data)
|
||||
reduce = (list(reduce)+[None]*5)[:5]
|
||||
function, args, state, listitems, dictitems = reduce
|
||||
args = list(args)
|
||||
if state is None:
|
||||
state = {}
|
||||
if listitems is not None:
|
||||
listitems = list(listitems)
|
||||
if dictitems is not None:
|
||||
dictitems = dict(dictitems)
|
||||
if function.__name__ == '__newobj__':
|
||||
function = args[0]
|
||||
args = args[1:]
|
||||
tag = 'tag:yaml.org,2002:python/object/new:'
|
||||
newobj = True
|
||||
else:
|
||||
tag = 'tag:yaml.org,2002:python/object/apply:'
|
||||
newobj = False
|
||||
function_name = '%s.%s' % (function.__module__, function.__name__)
|
||||
if not args and not listitems and not dictitems \
|
||||
and isinstance(state, dict) and newobj:
|
||||
return self.represent_mapping(
|
||||
'tag:yaml.org,2002:python/object:'+function_name, state)
|
||||
if not listitems and not dictitems \
|
||||
and isinstance(state, dict) and not state:
|
||||
return self.represent_sequence(tag+function_name, args)
|
||||
value = {}
|
||||
if args:
|
||||
value['args'] = args
|
||||
if state or not isinstance(state, dict):
|
||||
value['state'] = state
|
||||
if listitems:
|
||||
value['listitems'] = listitems
|
||||
if dictitems:
|
||||
value['dictitems'] = dictitems
|
||||
return self.represent_mapping(tag+function_name, value)
|
||||
|
||||
def represent_ordered_dict(self, data):
|
||||
# Provide uniform representation across different Python versions.
|
||||
data_type = type(data)
|
||||
tag = 'tag:yaml.org,2002:python/object/apply:%s.%s' \
|
||||
% (data_type.__module__, data_type.__name__)
|
||||
items = [[key, value] for key, value in data.items()]
|
||||
return self.represent_sequence(tag, [items])
|
||||
|
||||
Representer.add_representer(complex,
|
||||
Representer.represent_complex)
|
||||
|
||||
Representer.add_representer(tuple,
|
||||
Representer.represent_tuple)
|
||||
|
||||
Representer.add_representer(type,
|
||||
Representer.represent_name)
|
||||
|
||||
Representer.add_representer(collections.OrderedDict,
|
||||
Representer.represent_ordered_dict)
|
||||
|
||||
Representer.add_representer(types.FunctionType,
|
||||
Representer.represent_name)
|
||||
|
||||
Representer.add_representer(types.BuiltinFunctionType,
|
||||
Representer.represent_name)
|
||||
|
||||
Representer.add_representer(types.ModuleType,
|
||||
Representer.represent_module)
|
||||
|
||||
Representer.add_multi_representer(object,
|
||||
Representer.represent_object)
|
||||
|
||||
@ -1,227 +0,0 @@
|
||||
|
||||
__all__ = ['BaseResolver', 'Resolver']
|
||||
|
||||
from .error import *
|
||||
from .nodes import *
|
||||
|
||||
import re
|
||||
|
||||
class ResolverError(YAMLError):
|
||||
pass
|
||||
|
||||
class BaseResolver:
|
||||
|
||||
DEFAULT_SCALAR_TAG = 'tag:yaml.org,2002:str'
|
||||
DEFAULT_SEQUENCE_TAG = 'tag:yaml.org,2002:seq'
|
||||
DEFAULT_MAPPING_TAG = 'tag:yaml.org,2002:map'
|
||||
|
||||
yaml_implicit_resolvers = {}
|
||||
yaml_path_resolvers = {}
|
||||
|
||||
def __init__(self):
|
||||
self.resolver_exact_paths = []
|
||||
self.resolver_prefix_paths = []
|
||||
|
||||
@classmethod
|
||||
def add_implicit_resolver(cls, tag, regexp, first):
|
||||
if not 'yaml_implicit_resolvers' in cls.__dict__:
|
||||
implicit_resolvers = {}
|
||||
for key in cls.yaml_implicit_resolvers:
|
||||
implicit_resolvers[key] = cls.yaml_implicit_resolvers[key][:]
|
||||
cls.yaml_implicit_resolvers = implicit_resolvers
|
||||
if first is None:
|
||||
first = [None]
|
||||
for ch in first:
|
||||
cls.yaml_implicit_resolvers.setdefault(ch, []).append((tag, regexp))
|
||||
|
||||
@classmethod
|
||||
def add_path_resolver(cls, tag, path, kind=None):
|
||||
# Note: `add_path_resolver` is experimental. The API could be changed.
|
||||
# `new_path` is a pattern that is matched against the path from the
|
||||
# root to the node that is being considered. `node_path` elements are
|
||||
# tuples `(node_check, index_check)`. `node_check` is a node class:
|
||||
# `ScalarNode`, `SequenceNode`, `MappingNode` or `None`. `None`
|
||||
# matches any kind of a node. `index_check` could be `None`, a boolean
|
||||
# value, a string value, or a number. `None` and `False` match against
|
||||
# any _value_ of sequence and mapping nodes. `True` matches against
|
||||
# any _key_ of a mapping node. A string `index_check` matches against
|
||||
# a mapping value that corresponds to a scalar key which content is
|
||||
# equal to the `index_check` value. An integer `index_check` matches
|
||||
# against a sequence value with the index equal to `index_check`.
|
||||
if not 'yaml_path_resolvers' in cls.__dict__:
|
||||
cls.yaml_path_resolvers = cls.yaml_path_resolvers.copy()
|
||||
new_path = []
|
||||
for element in path:
|
||||
if isinstance(element, (list, tuple)):
|
||||
if len(element) == 2:
|
||||
node_check, index_check = element
|
||||
elif len(element) == 1:
|
||||
node_check = element[0]
|
||||
index_check = True
|
||||
else:
|
||||
raise ResolverError("Invalid path element: %s" % element)
|
||||
else:
|
||||
node_check = None
|
||||
index_check = element
|
||||
if node_check is str:
|
||||
node_check = ScalarNode
|
||||
elif node_check is list:
|
||||
node_check = SequenceNode
|
||||
elif node_check is dict:
|
||||
node_check = MappingNode
|
||||
elif node_check not in [ScalarNode, SequenceNode, MappingNode] \
|
||||
and not isinstance(node_check, str) \
|
||||
and node_check is not None:
|
||||
raise ResolverError("Invalid node checker: %s" % node_check)
|
||||
if not isinstance(index_check, (str, int)) \
|
||||
and index_check is not None:
|
||||
raise ResolverError("Invalid index checker: %s" % index_check)
|
||||
new_path.append((node_check, index_check))
|
||||
if kind is str:
|
||||
kind = ScalarNode
|
||||
elif kind is list:
|
||||
kind = SequenceNode
|
||||
elif kind is dict:
|
||||
kind = MappingNode
|
||||
elif kind not in [ScalarNode, SequenceNode, MappingNode] \
|
||||
and kind is not None:
|
||||
raise ResolverError("Invalid node kind: %s" % kind)
|
||||
cls.yaml_path_resolvers[tuple(new_path), kind] = tag
|
||||
|
||||
def descend_resolver(self, current_node, current_index):
|
||||
if not self.yaml_path_resolvers:
|
||||
return
|
||||
exact_paths = {}
|
||||
prefix_paths = []
|
||||
if current_node:
|
||||
depth = len(self.resolver_prefix_paths)
|
||||
for path, kind in self.resolver_prefix_paths[-1]:
|
||||
if self.check_resolver_prefix(depth, path, kind,
|
||||
current_node, current_index):
|
||||
if len(path) > depth:
|
||||
prefix_paths.append((path, kind))
|
||||
else:
|
||||
exact_paths[kind] = self.yaml_path_resolvers[path, kind]
|
||||
else:
|
||||
for path, kind in self.yaml_path_resolvers:
|
||||
if not path:
|
||||
exact_paths[kind] = self.yaml_path_resolvers[path, kind]
|
||||
else:
|
||||
prefix_paths.append((path, kind))
|
||||
self.resolver_exact_paths.append(exact_paths)
|
||||
self.resolver_prefix_paths.append(prefix_paths)
|
||||
|
||||
def ascend_resolver(self):
|
||||
if not self.yaml_path_resolvers:
|
||||
return
|
||||
self.resolver_exact_paths.pop()
|
||||
self.resolver_prefix_paths.pop()
|
||||
|
||||
def check_resolver_prefix(self, depth, path, kind,
|
||||
current_node, current_index):
|
||||
node_check, index_check = path[depth-1]
|
||||
if isinstance(node_check, str):
|
||||
if current_node.tag != node_check:
|
||||
return
|
||||
elif node_check is not None:
|
||||
if not isinstance(current_node, node_check):
|
||||
return
|
||||
if index_check is True and current_index is not None:
|
||||
return
|
||||
if (index_check is False or index_check is None) \
|
||||
and current_index is None:
|
||||
return
|
||||
if isinstance(index_check, str):
|
||||
if not (isinstance(current_index, ScalarNode)
|
||||
and index_check == current_index.value):
|
||||
return
|
||||
elif isinstance(index_check, int) and not isinstance(index_check, bool):
|
||||
if index_check != current_index:
|
||||
return
|
||||
return True
|
||||
|
||||
def resolve(self, kind, value, implicit):
|
||||
if kind is ScalarNode and implicit[0]:
|
||||
if value == '':
|
||||
resolvers = self.yaml_implicit_resolvers.get('', [])
|
||||
else:
|
||||
resolvers = self.yaml_implicit_resolvers.get(value[0], [])
|
||||
resolvers += self.yaml_implicit_resolvers.get(None, [])
|
||||
for tag, regexp in resolvers:
|
||||
if regexp.match(value):
|
||||
return tag
|
||||
implicit = implicit[1]
|
||||
if self.yaml_path_resolvers:
|
||||
exact_paths = self.resolver_exact_paths[-1]
|
||||
if kind in exact_paths:
|
||||
return exact_paths[kind]
|
||||
if None in exact_paths:
|
||||
return exact_paths[None]
|
||||
if kind is ScalarNode:
|
||||
return self.DEFAULT_SCALAR_TAG
|
||||
elif kind is SequenceNode:
|
||||
return self.DEFAULT_SEQUENCE_TAG
|
||||
elif kind is MappingNode:
|
||||
return self.DEFAULT_MAPPING_TAG
|
||||
|
||||
class Resolver(BaseResolver):
|
||||
pass
|
||||
|
||||
Resolver.add_implicit_resolver(
|
||||
'tag:yaml.org,2002:bool',
|
||||
re.compile(r'''^(?:yes|Yes|YES|no|No|NO
|
||||
|true|True|TRUE|false|False|FALSE
|
||||
|on|On|ON|off|Off|OFF)$''', re.X),
|
||||
list('yYnNtTfFoO'))
|
||||
|
||||
Resolver.add_implicit_resolver(
|
||||
'tag:yaml.org,2002:float',
|
||||
re.compile(r'''^(?:[-+]?(?:[0-9][0-9_]*)\.[0-9_]*(?:[eE][-+][0-9]+)?
|
||||
|\.[0-9_]+(?:[eE][-+][0-9]+)?
|
||||
|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\.[0-9_]*
|
||||
|[-+]?\.(?:inf|Inf|INF)
|
||||
|\.(?:nan|NaN|NAN))$''', re.X),
|
||||
list('-+0123456789.'))
|
||||
|
||||
Resolver.add_implicit_resolver(
|
||||
'tag:yaml.org,2002:int',
|
||||
re.compile(r'''^(?:[-+]?0b[0-1_]+
|
||||
|[-+]?0[0-7_]+
|
||||
|[-+]?(?:0|[1-9][0-9_]*)
|
||||
|[-+]?0x[0-9a-fA-F_]+
|
||||
|[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$''', re.X),
|
||||
list('-+0123456789'))
|
||||
|
||||
Resolver.add_implicit_resolver(
|
||||
'tag:yaml.org,2002:merge',
|
||||
re.compile(r'^(?:<<)$'),
|
||||
['<'])
|
||||
|
||||
Resolver.add_implicit_resolver(
|
||||
'tag:yaml.org,2002:null',
|
||||
re.compile(r'''^(?: ~
|
||||
|null|Null|NULL
|
||||
| )$''', re.X),
|
||||
['~', 'n', 'N', ''])
|
||||
|
||||
Resolver.add_implicit_resolver(
|
||||
'tag:yaml.org,2002:timestamp',
|
||||
re.compile(r'''^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]
|
||||
|[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?
|
||||
(?:[Tt]|[ \t]+)[0-9][0-9]?
|
||||
:[0-9][0-9] :[0-9][0-9] (?:\.[0-9]*)?
|
||||
(?:[ \t]*(?:Z|[-+][0-9][0-9]?(?::[0-9][0-9])?))?)$''', re.X),
|
||||
list('0123456789'))
|
||||
|
||||
Resolver.add_implicit_resolver(
|
||||
'tag:yaml.org,2002:value',
|
||||
re.compile(r'^(?:=)$'),
|
||||
['='])
|
||||
|
||||
# The following resolver is only for documentation purposes. It cannot work
|
||||
# because plain scalars cannot start with '!', '&', or '*'.
|
||||
Resolver.add_implicit_resolver(
|
||||
'tag:yaml.org,2002:yaml',
|
||||
re.compile(r'^(?:!|&|\*)$'),
|
||||
list('!&*'))
|
||||
|
||||
1435
src/yaml/scanner.py
@ -1,111 +0,0 @@
|
||||
|
||||
__all__ = ['Serializer', 'SerializerError']
|
||||
|
||||
from .error import YAMLError
|
||||
from .events import *
|
||||
from .nodes import *
|
||||
|
||||
class SerializerError(YAMLError):
|
||||
pass
|
||||
|
||||
class Serializer:
|
||||
|
||||
ANCHOR_TEMPLATE = 'id%03d'
|
||||
|
||||
def __init__(self, encoding=None,
|
||||
explicit_start=None, explicit_end=None, version=None, tags=None):
|
||||
self.use_encoding = encoding
|
||||
self.use_explicit_start = explicit_start
|
||||
self.use_explicit_end = explicit_end
|
||||
self.use_version = version
|
||||
self.use_tags = tags
|
||||
self.serialized_nodes = {}
|
||||
self.anchors = {}
|
||||
self.last_anchor_id = 0
|
||||
self.closed = None
|
||||
|
||||
def open(self):
|
||||
if self.closed is None:
|
||||
self.emit(StreamStartEvent(encoding=self.use_encoding))
|
||||
self.closed = False
|
||||
elif self.closed:
|
||||
raise SerializerError("serializer is closed")
|
||||
else:
|
||||
raise SerializerError("serializer is already opened")
|
||||
|
||||
def close(self):
|
||||
if self.closed is None:
|
||||
raise SerializerError("serializer is not opened")
|
||||
elif not self.closed:
|
||||
self.emit(StreamEndEvent())
|
||||
self.closed = True
|
||||
|
||||
#def __del__(self):
|
||||
# self.close()
|
||||
|
||||
def serialize(self, node):
|
||||
if self.closed is None:
|
||||
raise SerializerError("serializer is not opened")
|
||||
elif self.closed:
|
||||
raise SerializerError("serializer is closed")
|
||||
self.emit(DocumentStartEvent(explicit=self.use_explicit_start,
|
||||
version=self.use_version, tags=self.use_tags))
|
||||
self.anchor_node(node)
|
||||
self.serialize_node(node, None, None)
|
||||
self.emit(DocumentEndEvent(explicit=self.use_explicit_end))
|
||||
self.serialized_nodes = {}
|
||||
self.anchors = {}
|
||||
self.last_anchor_id = 0
|
||||
|
||||
def anchor_node(self, node):
|
||||
if node in self.anchors:
|
||||
if self.anchors[node] is None:
|
||||
self.anchors[node] = self.generate_anchor(node)
|
||||
else:
|
||||
self.anchors[node] = None
|
||||
if isinstance(node, SequenceNode):
|
||||
for item in node.value:
|
||||
self.anchor_node(item)
|
||||
elif isinstance(node, MappingNode):
|
||||
for key, value in node.value:
|
||||
self.anchor_node(key)
|
||||
self.anchor_node(value)
|
||||
|
||||
def generate_anchor(self, node):
|
||||
self.last_anchor_id += 1
|
||||
return self.ANCHOR_TEMPLATE % self.last_anchor_id
|
||||
|
||||
def serialize_node(self, node, parent, index):
|
||||
alias = self.anchors[node]
|
||||
if node in self.serialized_nodes:
|
||||
self.emit(AliasEvent(alias))
|
||||
else:
|
||||
self.serialized_nodes[node] = True
|
||||
self.descend_resolver(parent, index)
|
||||
if isinstance(node, ScalarNode):
|
||||
detected_tag = self.resolve(ScalarNode, node.value, (True, False))
|
||||
default_tag = self.resolve(ScalarNode, node.value, (False, True))
|
||||
implicit = (node.tag == detected_tag), (node.tag == default_tag)
|
||||
self.emit(ScalarEvent(alias, node.tag, implicit, node.value,
|
||||
style=node.style))
|
||||
elif isinstance(node, SequenceNode):
|
||||
implicit = (node.tag
|
||||
== self.resolve(SequenceNode, node.value, True))
|
||||
self.emit(SequenceStartEvent(alias, node.tag, implicit,
|
||||
flow_style=node.flow_style))
|
||||
index = 0
|
||||
for item in node.value:
|
||||
self.serialize_node(item, node, index)
|
||||
index += 1
|
||||
self.emit(SequenceEndEvent())
|
||||
elif isinstance(node, MappingNode):
|
||||
implicit = (node.tag
|
||||
== self.resolve(MappingNode, node.value, True))
|
||||
self.emit(MappingStartEvent(alias, node.tag, implicit,
|
||||
flow_style=node.flow_style))
|
||||
for key, value in node.value:
|
||||
self.serialize_node(key, node, None)
|
||||
self.serialize_node(value, node, key)
|
||||
self.emit(MappingEndEvent())
|
||||
self.ascend_resolver()
|
||||
|
||||
@ -1,104 +0,0 @@
|
||||
|
||||
class Token(object):
|
||||
def __init__(self, start_mark, end_mark):
|
||||
self.start_mark = start_mark
|
||||
self.end_mark = end_mark
|
||||
def __repr__(self):
|
||||
attributes = [key for key in self.__dict__
|
||||
if not key.endswith('_mark')]
|
||||
attributes.sort()
|
||||
arguments = ', '.join(['%s=%r' % (key, getattr(self, key))
|
||||
for key in attributes])
|
||||
return '%s(%s)' % (self.__class__.__name__, arguments)
|
||||
|
||||
#class BOMToken(Token):
|
||||
# id = '<byte order mark>'
|
||||
|
||||
class DirectiveToken(Token):
|
||||
id = '<directive>'
|
||||
def __init__(self, name, value, start_mark, end_mark):
|
||||
self.name = name
|
||||
self.value = value
|
||||
self.start_mark = start_mark
|
||||
self.end_mark = end_mark
|
||||
|
||||
class DocumentStartToken(Token):
|
||||
id = '<document start>'
|
||||
|
||||
class DocumentEndToken(Token):
|
||||
id = '<document end>'
|
||||
|
||||
class StreamStartToken(Token):
|
||||
id = '<stream start>'
|
||||
def __init__(self, start_mark=None, end_mark=None,
|
||||
encoding=None):
|
||||
self.start_mark = start_mark
|
||||
self.end_mark = end_mark
|
||||
self.encoding = encoding
|
||||
|
||||
class StreamEndToken(Token):
|
||||
id = '<stream end>'
|
||||
|
||||
class BlockSequenceStartToken(Token):
|
||||
id = '<block sequence start>'
|
||||
|
||||
class BlockMappingStartToken(Token):
|
||||
id = '<block mapping start>'
|
||||
|
||||
class BlockEndToken(Token):
|
||||
id = '<block end>'
|
||||
|
||||
class FlowSequenceStartToken(Token):
|
||||
id = '['
|
||||
|
||||
class FlowMappingStartToken(Token):
|
||||
id = '{'
|
||||
|
||||
class FlowSequenceEndToken(Token):
|
||||
id = ']'
|
||||
|
||||
class FlowMappingEndToken(Token):
|
||||
id = '}'
|
||||
|
||||
class KeyToken(Token):
|
||||
id = '?'
|
||||
|
||||
class ValueToken(Token):
|
||||
id = ':'
|
||||
|
||||
class BlockEntryToken(Token):
|
||||
id = '-'
|
||||
|
||||
class FlowEntryToken(Token):
|
||||
id = ','
|
||||
|
||||
class AliasToken(Token):
|
||||
id = '<alias>'
|
||||
def __init__(self, value, start_mark, end_mark):
|
||||
self.value = value
|
||||
self.start_mark = start_mark
|
||||
self.end_mark = end_mark
|
||||
|
||||
class AnchorToken(Token):
|
||||
id = '<anchor>'
|
||||
def __init__(self, value, start_mark, end_mark):
|
||||
self.value = value
|
||||
self.start_mark = start_mark
|
||||
self.end_mark = end_mark
|
||||
|
||||
class TagToken(Token):
|
||||
id = '<tag>'
|
||||
def __init__(self, value, start_mark, end_mark):
|
||||
self.value = value
|
||||
self.start_mark = start_mark
|
||||
self.end_mark = end_mark
|
||||
|
||||
class ScalarToken(Token):
|
||||
id = '<scalar>'
|
||||
def __init__(self, value, plain, start_mark, end_mark, style=None):
|
||||
self.value = value
|
||||
self.plain = plain
|
||||
self.start_mark = start_mark
|
||||
self.end_mark = end_mark
|
||||
self.style = style
|
||||
|
||||
49
todo.md
@ -1,49 +0,0 @@
|
||||
# To-do:
|
||||
|
||||
## Support for more connector types
|
||||
|
||||
* Inline connectors (IDC)
|
||||
* Possibly join two logical wires into one physical wire, add up length for BOM creation
|
||||
* Designators like W1_1, W1_2 or similar to group them?
|
||||
|
||||
## Support for more wire types
|
||||
|
||||
* Coax cables
|
||||
* Graphical representation
|
||||
* Twisted pairs
|
||||
* Logical representation
|
||||
* Graphical representation
|
||||
* Ribbon cables
|
||||
* Folds
|
||||
* Splits
|
||||
* Orientation of IDC connectors
|
||||
|
||||
## Support for more links/connections
|
||||
|
||||
* Cable splicing
|
||||
* as pseudo-connector?
|
||||
* Heatshrink / sheathing
|
||||
|
||||
## Visualization
|
||||
|
||||
* Parse and render double-colored, striped cables ('RDBU' etc)
|
||||
* Display picture of connector underneath (including pin 1 location)
|
||||
|
||||
## Export
|
||||
|
||||
* Export to PDF with frame, title block, ...
|
||||
|
||||
## Other
|
||||
|
||||
* Imrpove tutorial texts
|
||||
* Create syntax reference / cheat sheet
|
||||
* Set global parameters (show_pins, ...) and allow override on per-item basis
|
||||
* Allow custom GraphViz code before/after WireViz-generated code
|
||||
* Make "unit tests" for different features/situations
|
||||
* Missing parameters
|
||||
* Connection formats
|
||||
* single wire 1
|
||||
* multiple wires [1,2,3]
|
||||
* wire ranges [1-10]
|
||||
* Loops
|
||||
* ...
|
||||
@ -221,7 +221,7 @@ connections:
|
||||
- # attach ferrules
|
||||
- F1 # no need for list of connections; one ferrule per wire is auto-generated and attached
|
||||
- W1: [1-4] # a new ferrule is auto-generated for each wire
|
||||
- # attach connectors (separetely from ferrules)
|
||||
- # attach connectors (separately from ferrules)
|
||||
- W1: [1-4]
|
||||
- X1: [1-4]
|
||||
```
|
||||
@ -262,7 +262,7 @@ ferrules: # ferrules
|
||||
|
||||
cables:
|
||||
W1:
|
||||
category: bundle # budnle
|
||||
category: bundle # bundle
|
||||
length: 0.3
|
||||
gauge: 0.5 mm2
|
||||
colors: [YE, BK, BK, RD] # custom colors, wirecount is implicit
|
||||
@ -271,7 +271,7 @@ connections:
|
||||
- # attach ferrules
|
||||
- F_05
|
||||
- W1: [1,4] # a new ferrule is auto-generated for each wire
|
||||
- # attach connectors (separetely from ferrules)
|
||||
- # attach connectors (separately from ferrules)
|
||||
- W1: [1-4]
|
||||
- X1: [1-4]
|
||||
-
|
||||
|
||||
@ -21,6 +21,6 @@ connections:
|
||||
- # attach ferrules
|
||||
- F1 # no need for list of connections; one ferrule per wire is auto-generated and attached
|
||||
- W1: [1-4] # a new ferrule is auto-generated for each wire
|
||||
- # attach connectors (separetely from ferrules)
|
||||
- # attach connectors (separately from ferrules)
|
||||
- W1: [1-4]
|
||||
- X1: [1-4]
|
||||
|
||||
@ -17,7 +17,7 @@ ferrules: # ferrules
|
||||
|
||||
cables:
|
||||
W1:
|
||||
category: bundle # budnle
|
||||
category: bundle # bundle
|
||||
length: 0.3
|
||||
gauge: 0.5 mm2
|
||||
colors: [YE, BK, BK, RD] # custom colors, wirecount is implicit
|
||||
@ -26,7 +26,7 @@ connections:
|
||||
- # attach ferrules
|
||||
- F_05
|
||||
- W1: [1,4] # a new ferrule is auto-generated for each wire
|
||||
- # attach connectors (separetely from ferrules)
|
||||
- # attach connectors (separately from ferrules)
|
||||
- W1: [1-4]
|
||||
- X1: [1-4]
|
||||
-
|
||||
|
||||