bomkit 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(.venv/Scripts/python.exe -c \":*)"
5
+ ]
6
+ }
7
+ }
@@ -0,0 +1,27 @@
1
+ name: Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+ branches: [master]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ python-version: ["3.11", "3.12", "3.13"]
15
+
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - uses: actions/setup-python@v5
20
+ with:
21
+ python-version: ${{ matrix.python-version }}
22
+
23
+ - name: Install package
24
+ run: pip install -e ".[dev]"
25
+
26
+ - name: Run tests
27
+ run: pytest tests/
@@ -0,0 +1,119 @@
1
+ # Created by https://www.gitignore.io/api/python
2
+ # Edit at https://www.gitignore.io/?templates=python
3
+
4
+ .vscode/
5
+ development/
6
+ temp/
7
+ *.code-workspace
8
+ scratch/
9
+ run/
10
+ Example/_*.xlsx
11
+ env/
12
+ .venv/
13
+
14
+ ### Python ###
15
+ # Byte-compiled / optimized / DLL files
16
+ __pycache__/
17
+ *.py[cod]
18
+ *$py.class
19
+
20
+ # C extensions
21
+ *.so
22
+
23
+ # Distribution / packaging
24
+ .Python
25
+ build/
26
+ develop-eggs/
27
+ dist/
28
+ downloads/
29
+ eggs/
30
+ .eggs/
31
+ lib/
32
+ lib64/
33
+ parts/
34
+ sdist/
35
+ var/
36
+ wheels/
37
+ pip-wheel-metadata/
38
+ share/python-wheels/
39
+ *.egg-info/
40
+ .installed.cfg
41
+ *.egg
42
+ MANIFEST
43
+
44
+ # PyInstaller
45
+ # Usually these files are written by a python script from a template
46
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
47
+ *.manifest
48
+ *.spec
49
+
50
+ # Installer logs
51
+ pip-log.txt
52
+ pip-delete-this-directory.txt
53
+
54
+ # Unit test / coverage reports
55
+ htmlcov/
56
+ .tox/
57
+ .nox/
58
+ .coverage
59
+ .coverage.*
60
+ .cache
61
+ nosetests.xml
62
+ coverage.xml
63
+ *.cover
64
+ .hypothesis/
65
+ .pytest_cache/
66
+
67
+ # Translations
68
+ *.mo
69
+ *.pot
70
+
71
+ # Scrapy stuff:
72
+ .scrapy
73
+
74
+ # Sphinx documentation
75
+ docs/_build/
76
+
77
+ # PyBuilder
78
+ target/
79
+
80
+ # pyenv
81
+ .python-version
82
+
83
+ # pipenv
84
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
85
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
86
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
87
+ # install all needed dependencies.
88
+ #Pipfile.lock
89
+
90
+ # celery beat schedule file
91
+ celerybeat-schedule
92
+
93
+ # SageMath parsed files
94
+ *.sage.py
95
+
96
+ # Spyder project settings
97
+ .spyderproject
98
+ .spyproject
99
+
100
+ # Rope project settings
101
+ .ropeproject
102
+
103
+ # Mr Developer
104
+ .mr.developer.cfg
105
+ .project
106
+ .pydevproject
107
+
108
+ # mkdocs documentation
109
+ /site
110
+
111
+ # mypy
112
+ .mypy_cache/
113
+ .dmypy.json
114
+ dmypy.json
115
+
116
+ # Pyre type checker
117
+ .pyre/
118
+
119
+ # End of https://www.gitignore.io/api/python
@@ -0,0 +1,43 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.0] - 2026-03-02
11
+ Initial public release as `bomkit` (formerly `pybom`).
12
+
13
+ ### Added
14
+ - Interactive TUI browser (`--browse` mode) powered by Textual
15
+ - Initial test suite
16
+ - GitHub Actions CI workflow
17
+ - Type hints throughout `BOM.py`
18
+ - Assembly BOM name read from Excel sheet name
19
+
20
+ ### Changed
21
+ - `BOM.from_file()` made private (`_from_file()`)
22
+ - `QTY` method returning Python integers
23
+
24
+
25
+ ---
26
+
27
+
28
+ ## Pre-release history (as `pybom`)
29
+
30
+ ## 0.2.0 - 2023
31
+
32
+ ### Added
33
+ - `BOM.single_file()` for single-file BOMs
34
+
35
+ ## 0.1.0 - 2020
36
+
37
+ ### Added
38
+ - Core `BOM`, `Item`, `ItemLink`, and `PartsDB` data model
39
+ - `BOM.from_folder()` for multi-file BOMs
40
+
41
+
42
+ [Unreleased]: https://github.com/robsiegwart/bomkit/compare/v0.1.0...HEAD
43
+ [0.1.0]: https://github.com/robsiegwart/bomkit/releases/tag/v0.1.0
Binary file
Binary file
Binary file
Binary file
bomkit-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Rob Siegwart
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
bomkit-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,280 @@
1
+ Metadata-Version: 2.4
2
+ Name: bomkit
3
+ Version: 0.1.0
4
+ Summary: Bill of materials processing utilities
5
+ Author-email: Rob Siegwart <rob@robsiegwart.com>
6
+ License: MIT
7
+ License-File: LICENSE
8
+ Keywords: bom,engineering,manufacturing
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Manufacturing
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Topic :: Scientific/Engineering
14
+ Requires-Python: >=3.8
15
+ Requires-Dist: anytree>=2.12
16
+ Requires-Dist: openpyxl>=3.1
17
+ Requires-Dist: pandas>=2.0
18
+ Requires-Dist: textual>=0.50
19
+ Provides-Extra: dev
20
+ Requires-Dist: pytest; extra == 'dev'
21
+ Requires-Dist: pytest-asyncio; extra == 'dev'
22
+ Description-Content-Type: text/markdown
23
+
24
+ # bomkit
25
+
26
+ ![Tests](https://github.com/robsiegwart/bomkit/actions/workflows/test.yml/badge.svg)
27
+
28
+ A Python program for flattening a layered bill-of-material (BOM) based on Excel
29
+ files. Part quantities are combined and a total quantity or
30
+ minimum-required-package-to-buy amount is calculated, in addition to extended
31
+ costs. A tree structure of the BOM hierarchy can also be created and converted
32
+ to DOT syntax for further graphics generation.
33
+
34
+ The functionality can be accessed in three ways:
35
+
36
+ | Method | Description |
37
+ |--------|-------------|
38
+ | Interactive TUI (terminal-based interface) | Launch with `bomkit [directory]` |
39
+ | API | In Python, use `from bomkit import BOM`, then `BOM.from_folder()` or `BOM.single_file()` |
40
+ | Command line | Run with `bomkit [-h] (-f FILE \| -d FOLDER) action` |
41
+
42
+
43
+ ## Motivation
44
+
45
+ The main problem solved is to combine identical parts from various
46
+ sub-assemblies and locations in your product BOM. Additionally, it is designed
47
+ to be used with Excel since Excel is common and does not require a separate
48
+ program or server.
49
+
50
+ Flattening tells you the total QTY of a part when it may be used in many
51
+ sub-assemblies and levels in your product structure. This is necessary to
52
+ calculate the total QTY of a part and therefore determine the mininum packages
53
+ of the product to buy, since many parts come in packs greater than QTY 1.
54
+
55
+ ## Structure
56
+
57
+ There are two methods for storing data for parts and assemblies: multi-file or
58
+ single file.
59
+
60
+ ### Multi-File
61
+
62
+ In a separate directory, put an Excel file named *Parts List.xlsx* to serve as
63
+ the master parts list \"database\". Then, each additional assembly is described
64
+ by a separate .xlsx file. Thus you might have:
65
+
66
+ my_project/
67
+ Parts list.xlsx <-- master parts list
68
+ SKA-100.xlsx <-- top level/root assembly
69
+ TR-01.xlsx <-- subassembly
70
+ WH-01.xlsx <-- subassembly
71
+
72
+ Root and sub-assemblies are inferred from item number relationships and are not
73
+ required to be explicitly identified.
74
+
75
+ *Parts list.xlsx* serves as the single point of reference for part information.
76
+ For example, it may have the following:
77
+
78
+ | PN | Name | Description | Supplier | Supplier PN | Pkg QTY | Pkg Price |
79
+ | --------- | ----------- | ------------------------------ | ---------------------- | ------------- | --------- | ---------- |
80
+ | SK1001-01 | Deck | Pavement Pro 9" Maple Deck | Grindstone Supply Co. | BRX-02 | 1 | 67.95 |
81
+ | SK1002-01 | Truck | HollowKing Standard Trucks | Grindstone Supply Co. | TR1-A | 1 | 28.95 |
82
+ | SK1003-01 | Bearing | ABEC-7 Steel Bearings | BoltRun Hardware | 74295-942 | 1 | 9.95 |
83
+ | SK1004-01 | Wheel | SlickCore 54mm Cruiser Wheels | Grindstone Supply Co. | WHL-PRX | 4 | 44.95 |
84
+ | SK1005-01 | Screw | 10-32, 1", Phillips | BoltRun Hardware | 92220A | 25 | 12.49 |
85
+ | SK1006-01 | Nut | 10-32 | BoltRun Hardware | 95479A | 25 | 9.89 |
86
+ | SK1007-01 | Grip Tape | SuperStick 9" | BoltRun Hardware | GTSS99 | 1 | 8.95 |
87
+
88
+ For each assembly, all that is required is the part identification number and
89
+ quantity which correspond to the following fields:
90
+
91
+ - PN
92
+ - QTY
93
+
94
+ Example wheel assembly (1 wheel + 2 bearings):
95
+
96
+ | PN | QTY |
97
+ | ----------- | ----- |
98
+ | SK1004-01 | 1 |
99
+ | SK1003-01 | 2 |
100
+
101
+ Certain fields are used in calculating totals, such as in `BOM.BOM.summary`,
102
+ which are:
103
+
104
+ `Pkg QTY`
105
+ : The quantity of items in a specific supplier SKU (i.e. a bag of 100 screws)
106
+
107
+ `Pkg Price`
108
+ : The cost of a specific supplier SKU
109
+
110
+
111
+ ### Single File
112
+
113
+ A single Excel file is used to store all part and assembly data through the use
114
+ of Excel tabs.
115
+
116
+ The conventions for the single file approach are the same as the multi-file
117
+ approach, with the following exceptions:
118
+
119
+ - The first (left-most) Excel tab is treated as the Parts List "database",
120
+ regardless of its name
121
+ - All tabs/sheets to the right are interpreted as assemblies, with the sheet
122
+ name as the assembly part number (PN)
123
+
124
+
125
+ ## Usage
126
+
127
+ Install with pip via `pip install .` <!-- TODO: add PyPI link when published -->
128
+
129
+ Set up your data with either the multi-file or single file approach.
130
+
131
+ ### TUI Browser
132
+
133
+ In a terminal, browse to the folder containing your BOM files and issue the
134
+ command `bomkit` with no arguments (or issue the path to your directiry, e.g.
135
+ `bomkit /path/to/your/project`). This will cause it to enter the browser mode
136
+ where you can interact with your BOM hierarchy and view derived properties such
137
+ as the aggregated parts list and tree structure.
138
+
139
+ The default screen shows the top-level assembly and its direct-child parts and
140
+ assemblies. You can navigate down the hierarchy with the ⬆️ and ⬇️ arrow keys
141
+ and by selecting an assembly and pressing `Enter` to view its child parts and
142
+ assemblies. Pressing `Enter` on a part will show its details. Use the left arrow
143
+ key ⬅️ or `Esc` to return to the parent assembly. You can also access different
144
+ views and derived properties using the command keys listed at the bottom of the
145
+ screen, such as `t` for a tree view. Assemblies are shown in cyan and bold text.
146
+ The top row shows a breadcrumb of the current location in the BOM hierarchy.
147
+
148
+ The commands at the bottom of the screen are:
149
+
150
+ - `t` for a tree view of the full BOM hierarchy
151
+ - `p` for a part list view (all the parts in the Parts List file
152
+ - `a` for a list of all the assemblies in the BOM
153
+ - `s` for a summary view (aggregated parts list with total QTY and purchase
154
+ QTY)
155
+
156
+ ![TUI Browser's main screen view](doc/images/TUI-browser-main-screen.png)
157
+
158
+
159
+ ### API Usage
160
+
161
+ ```python
162
+ from bomkit import BOM
163
+
164
+ # Multi-file
165
+ bom = BOM.from_folder(FOLDER)
166
+
167
+ # Single file
168
+ bom = BOM.single_file(FILENAME)
169
+ ```
170
+
171
+ This returns a `BOM` object with properties on it you can retrieve:
172
+
173
+
174
+ `BOM.parts`
175
+ : Get a list of all direct-child parts
176
+
177
+ ```
178
+ >>> print(bom.parts)
179
+ [Part SK1001-01, Part SK1005-01, Part SK1006-01, Part SK1007-01]
180
+ ```
181
+
182
+ `BOM.assemblies`
183
+ : Get a list of all direct-child assemblies
184
+
185
+ ```
186
+ >>> print(bom.assemblies)
187
+ [TR-01]
188
+ ```
189
+
190
+ `BOM.aggregate`
191
+ : Get the aggregated quantity of each part/assembly from the current
192
+ BOM level down
193
+
194
+ ```
195
+ >>> print(bom.aggregate)
196
+ {'SK1001-01': 1, 'SK1005-01': 8, 'SK1006-01': 8, 'SK1007-01': 1, 'SK1002-01': 2, 'SK1004-01': 4, 'SK1003-01': 8}
197
+ ```
198
+
199
+ `BOM.summary`
200
+ : Get a summary in the form of a DataFrame containing the master parts
201
+ list with each item's aggregated quantity and the required packages
202
+ to buy (`Purchase QTY`) if the `Pkg QTY` field is not 1.
203
+
204
+ ```
205
+ >>> print(bom.summary)
206
+ PN Name Description ... Total QTY Purchase QTY Subtotal
207
+ 0 SK1001-01 Deck Pavement Pro 9" Maple Deck ... 1 1 67.95
208
+ 1 SK1002-01 Truck HollowKing Standard Trucks ... 2 2 57.90
209
+ 2 SK1003-01 Bearing ABEC-7 Steel Bearings ... 8 8 27.92
210
+ 3 SK1004-01 Wheel SlickCore 54mm Cruiser Wheels ... 4 1 44.95
211
+ 4 SK1005-01 Screw 10-32, 1”, Phillips ... 8 1 12.49
212
+ 5 SK1006-01 Nut 10-32 ... 8 1 9.89
213
+ 6 SK1007-01 Grip tape SuperStick 9” ... 1 1 8.95
214
+ ```
215
+
216
+ `BOM.tree`
217
+ : Return a string representation of the BOM tree hierarchy
218
+
219
+ ```
220
+ >>> print(bom.tree)
221
+ SKA-100
222
+ ├── Part SK1001-01
223
+ ├── TR-01
224
+ │ ├── Part SK1002-01
225
+ │ └── WH-01
226
+ │ ├── Part SK1004-01
227
+ │ └── Part SK1003-01
228
+ ├── Part SK1005-01
229
+ ├── Part SK1006-01
230
+ └── Part SK1007-01
231
+ ```
232
+
233
+ Calling this on child assemblies shows the tree from that reference point:
234
+ ```
235
+ >>> bom.assemblies
236
+ [TR-01]
237
+ >>> print(bom.assemblies[0].tree)
238
+ TR-01
239
+ ├── Part SK1002-01
240
+ └── WH-01
241
+ ├── Part SK1004-01
242
+ └── Part SK1003-01
243
+ ```
244
+
245
+ ### Command Line Usage
246
+
247
+ Functionality is extended to the command line where the flags `-f` and `-d` are
248
+ used to specify the name of a file for single-file mode or a folder for
249
+ multi-file mode, respectively.
250
+
251
+ `action` is what to do with the imported data, which just maps to a property
252
+ on the top-level `BOM` object.
253
+
254
+ This method is not persistent and is meant for quick one-off retrieval of information.
255
+
256
+ ```
257
+ > bomkit [-h] (-f FILE | -d FOLDER) action
258
+ ```
259
+
260
+ ```
261
+ > bomkit -d Example tree
262
+ SKA-100
263
+ ├── Part SK1001-01
264
+ ├── TR-01
265
+ │ ├── Part SK1002-01
266
+ │ └── WH-01
267
+ │ ├── Part SK1004-01
268
+ │ └── Part SK1003-01
269
+ ├── Part SK1005-01
270
+ ├── Part SK1006-01
271
+ └── Part SK1007-01
272
+ ```
273
+
274
+ Dependencies
275
+ ------------
276
+
277
+ - *pandas*
278
+ - *anytree*
279
+ - *openpyxl*
280
+ - *textual*