OpenPartsLibrary 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,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Aleksander Sadowski
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.
@@ -0,0 +1,20 @@
1
+ Metadata-Version: 2.4
2
+ Name: OpenPartsLibrary
3
+ Version: 0.1.0
4
+ Summary: Python library for creating a database of hardware components for manufacturing
5
+ Home-page: https://github.com/alekssadowski95/OpenPartsLibrary
6
+ Author: Aleksander Sadowski
7
+ Author-email: aleksander.sadowski@alsado.de
8
+ License: MIT
9
+ Classifier: Development Status :: 1 - Planning
10
+ Classifier: Intended Audience :: Science/Research
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ License-File: LICENSE
14
+ Dynamic: author
15
+ Dynamic: author-email
16
+ Dynamic: classifier
17
+ Dynamic: home-page
18
+ Dynamic: license
19
+ Dynamic: license-file
20
+ Dynamic: summary
@@ -0,0 +1,10 @@
1
+ LICENSE
2
+ README.md
3
+ setup.py
4
+ OpenPartsLibrary.egg-info/PKG-INFO
5
+ OpenPartsLibrary.egg-info/SOURCES.txt
6
+ OpenPartsLibrary.egg-info/dependency_links.txt
7
+ OpenPartsLibrary.egg-info/top_level.txt
8
+ openpartslibrary/__init__.py
9
+ openpartslibrary/db.py
10
+ openpartslibrary/models.py
@@ -0,0 +1 @@
1
+ openpartslibrary
@@ -0,0 +1,20 @@
1
+ Metadata-Version: 2.4
2
+ Name: OpenPartsLibrary
3
+ Version: 0.1.0
4
+ Summary: Python library for creating a database of hardware components for manufacturing
5
+ Home-page: https://github.com/alekssadowski95/OpenPartsLibrary
6
+ Author: Aleksander Sadowski
7
+ Author-email: aleksander.sadowski@alsado.de
8
+ License: MIT
9
+ Classifier: Development Status :: 1 - Planning
10
+ Classifier: Intended Audience :: Science/Research
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ License-File: LICENSE
14
+ Dynamic: author
15
+ Dynamic: author-email
16
+ Dynamic: classifier
17
+ Dynamic: home-page
18
+ Dynamic: license
19
+ Dynamic: license-file
20
+ Dynamic: summary
@@ -0,0 +1,131 @@
1
+ # OpenPartsLibrary
2
+ **OpenPartsLibrary** is a Python library designed to serve as a centralized parts database for Bill of Materials (BOM), Product Data Management (PDM), and Product Lifecycle Management (PLM) systems. It provides structured data models and APIs for managing components, part metadata, sourcing, and lifecycle states. OpenPartsLibrary streamlines integration with engineering workflows, enabling consistent part usage and traceability across design and manufacturing processes.
3
+
4
+ ## Quickstart
5
+
6
+ Install the openpartslibrary via pip
7
+ ```console
8
+ pip install openpartslibrary
9
+ ```
10
+
11
+ A minimal OpenPartsLibrary application looks something like this:
12
+ ```python
13
+ from openpartslibrary.db import PartsLibrary
14
+
15
+ pl = PartsLibrary()
16
+
17
+ pl.display()
18
+ ```
19
+
20
+ This will give you the following output, loading all the integrated parts of the library:
21
+ ```console
22
+ id uuid number name ... supplier manufacturer_number unit_price currency
23
+ 0 1 7dd559e06e1044c9b66e4a61df1072b6 SCRW-1000 Screw Type A 5mm ... Acme Fasteners MFG-625535 0.86 EUR
24
+ 1 2 ced16afd527e483db362f44d6fcedd82 SCRW-1001 Screw Type A 5mm ... In-House Manufacturing MFG-807818 4.02 EUR
25
+ 2 3 e3f8a20ab4974e45bca023a31c50e862 SCRW-1002 Screw Type C 2mm ... Precision Screws Ltd. MFG-543204 4.13 EUR
26
+ 3 4 7115fbc429594f09881181a3503b62db SCRW-1003 Screw Type B 3mm ... In-House Manufacturing MFG-916662 3.52 EUR
27
+ 4 5 8381dfa595854aa78b9d373d8a3f3f63 SCRW-1004 Screw Type A 1mm ... In-House Manufacturing MFG-742978 0.38 EUR
28
+ .. ... ... ... ... ... ... ... ... ...
29
+ 115 116 67f3f0ec88974cdc8e9ac4eea5cf1351 SCRW-1115 Screw Type B 1mm ... In-House Manufacturing MFG-406022 3.95 EUR
30
+ 116 117 a685e7b7135f48579a34ca45cf6baafe SCRW-1116 Screw Type B 10mm ... In-House Manufacturing MFG-230904 2.99 EUR
31
+ 117 118 c5c256a8a8b04972ab87ef84110f7d5a SCRW-1117 Screw Type A 4mm ... BoltCo MFG-343539 0.23 EUR
32
+ 118 119 2b9eda46cb8b45e093c084a437f01ba2 SCRW-1118 Screw Type B 1mm ... Precision Screws Ltd. MFG-247256 4.28 EUR
33
+ 119 120 39a71a5ed7224ee0bf5e919870ebe0a3 SCRW-1119 Screw Type D 4mm ... HexTech MFG-293100 2.06 EUR
34
+
35
+ [120 rows x 24 columns]
36
+ ```
37
+
38
+ ## Working with the parts library
39
+
40
+ Creating a new part in the library:
41
+ ```python
42
+ from openpartslibrary.models import Part
43
+
44
+ new_part = Part(
45
+ number='SCRW-2001',
46
+ name='Screw Type Z (Special) M5x14',
47
+ description='A special kind of screw for safety switches',
48
+ revision="1",
49
+ lifecycle_state="In Work",
50
+ owner='Max Mustermann',
51
+ material='Steel',
52
+ mass=0.03,
53
+ dimension_x=0.02,
54
+ dimension_y=0.005,
55
+ dimension_z=0.005,
56
+ quantity=100,
57
+ cad_reference='CAD REFERENCE',
58
+ attached_documents_reference='DOCUMENTS REFERENCE',
59
+ lead_time=10,
60
+ make_or_buy='make',
61
+ supplier='In-House Manufacturing',
62
+ manufacturer_number='MFN-100001',
63
+ unit_price=0.45,
64
+ currency='EUR'
65
+ )
66
+ pl.session.add(new_part)
67
+ pl.session.commit()
68
+ pl.display_reduced()
69
+ ```
70
+
71
+ Loading a part from the library:
72
+ ```python
73
+ part = pl.session.query(Part).filter(Part.number == 'SCRW-1002').first()
74
+ print(part)
75
+ ```
76
+
77
+ Modifying a part from the library:
78
+ ```python
79
+ part = pl.session.query(Part).filter(Part.number == 'SCRW-2001').first()
80
+ part.quantity -= 10
81
+ pl.session.commit()
82
+ pl.display_reduced()
83
+ ```
84
+
85
+ Deleting a part from the library:
86
+ ```python
87
+ part = pl.session.query(Part).filter(Part.number == 'SCRW-1003').delete()
88
+ pl.session.commit()
89
+ pl.display_reduced()
90
+ ```
91
+
92
+ Getting the total value of all parts in the library:
93
+ ```python
94
+ print('Total value of all parts in the library: ' + str(pl.total_value()) + ' EUR')
95
+ ```
96
+
97
+ Creating parts from a parts list in a Excel-spreadsheet (*.xlsx). Take note, that the spreadsheet needs to implement the schema specified in this repository:
98
+ ```python
99
+ pl.create_parts_from_spreadsheet('C:/Users/Work/Documents/Github/OpenPartsLibrary/openpartslibrary/sample/parts_data_sample.xlsx')
100
+ ```
101
+
102
+ ## Part schema
103
+ This table outlines the `Part` properties used in the OpenPartsLibrary.
104
+
105
+ | Property | Description |
106
+ |----------|-------------|
107
+ | `number` | Unique identifier for the part, often alphanumeric (e.g., `"MTR-12345"`). |
108
+ | `name` | Descriptive name of the part, typically used for display and search. |
109
+ | `description` | Detailed explanation of what the part is and its intended function. |
110
+ | `revision` | Version or iteration of the part (e.g., `"6"`). |
111
+ | `lifecycle_state` | Current status in the engineering lifecycle, like `"In Work"`, `"Released"`, `"Obsolete"`. |
112
+ | `owner` | Responsible person for the part. |
113
+ | `date_created` | Timestamp of when the part was first created in the system. |
114
+ | `date_modified` | Timestamp of the most recent update to the part. |
115
+ | `material` | The material from which the part is made (e.g., `"Aluminum 6061"`, `"ABS"`). |
116
+ | `mass` | Mass of the part, in kilograms. |
117
+ | `dimensions_x` | Length of the part along the X-axis, in millimeters. |
118
+ | `dimensions_y` | Width of the part along the Y-axis, in millimeters. |
119
+ | `dimensions_z` | Height of the part along the Z-axis, in millimeters. |
120
+ | `quantity` | Number of units of this part that are available. |
121
+ | `cad_file_reference` | Reference to the associated 3D CAD file (e.g. *.FCStd). |
122
+ | `attached_documents_reference` | References to external documents (e.g., datasheets, certifications). |
123
+ | `lead_time` | Expected procurement time, in days. |
124
+ | `make_or_buy` | Indicates whether the part is manufactured internally (`"Make"`) or externally sourced (`"Buy"`). |
125
+ | `supplier` | Preferred supplier or vendor name. |
126
+ | `manufacturer_number` | Vendor-specific identifier for the part, if purchased externally. |
127
+ | `unit_price` | Cost per individual unit of the part (e.g., `12.75`). |
128
+ | `currency` | Currency of the unit price (e.g., `EUR`). |
129
+
130
+
131
+ `id` and `uuid` will also be used internally, but database users does not have to worry about those.
File without changes
@@ -0,0 +1,87 @@
1
+ from sqlalchemy import create_engine
2
+ from sqlalchemy.orm import sessionmaker
3
+
4
+ import pandas as pd
5
+
6
+ from datetime import datetime
7
+
8
+ from .models import Base, Part
9
+
10
+
11
+ class PartsLibrary:
12
+ def __init__(self):
13
+ import os
14
+ sqlite_path = os.path.join(os.path.dirname(__file__), 'data', 'parts.db')
15
+ print(sqlite_path)
16
+ self.engine = create_engine('sqlite:///' + sqlite_path)
17
+
18
+ Base.metadata.create_all(self.engine)
19
+
20
+ self.session_factory = sessionmaker(bind=self.engine)
21
+ self.session = self.session_factory()
22
+
23
+ def display(self):
24
+ part_table = pd.read_sql_table(table_name="parts", con=self.engine)
25
+
26
+ pd.set_option('display.max_columns', 8)
27
+ pd.set_option('display.width', 240)
28
+
29
+ print(part_table)
30
+
31
+ def display_reduced(self):
32
+ part_table = pd.read_sql_table(table_name="parts", con=self.engine)
33
+ reduced_part_table = part_table[["id", "number", "name", "quantity", "mass", "lead_time", "supplier", "unit_price", "currency"]]
34
+ pd.set_option('display.max_columns', 9)
35
+ pd.set_option('display.width', 200)
36
+ print(reduced_part_table)
37
+
38
+
39
+ def delete_all(self):
40
+ self.session.query(Part).delete()
41
+ self.session.commit()
42
+
43
+ def create_parts_from_spreadsheet(self, file_path):
44
+ df = pd.read_excel(file_path)
45
+
46
+ parts = []
47
+ for _, row in df.iterrows():
48
+ part = Part(
49
+ uuid=row["uuid"],
50
+ number=row["number"],
51
+ name=row["name"],
52
+ description=row.get("description", "No description"),
53
+ revision=str(row.get("revision", "1")),
54
+ lifecycle_state=row.get("lifecycle_state", "In Work"),
55
+ owner=row.get("owner", "system"),
56
+ date_created=row.get("date_created", datetime.utcnow()),
57
+ date_modified=row.get("date_modified", datetime.utcnow()),
58
+ material=row.get("material"),
59
+ mass=row.get("mass"),
60
+ dimension_x=row.get("dimension_x"),
61
+ dimension_y=row.get("dimension_y"),
62
+ dimension_z=row.get("dimension_z"),
63
+ quantity=row.get("quantity", 0),
64
+ cad_reference=row.get("cad_reference"),
65
+ attached_documents_reference=row.get("attached_documents_reference"),
66
+ lead_time=row.get("lead_time"),
67
+ make_or_buy=row.get("make_or_buy"),
68
+ supplier=row.get("supplier"),
69
+ manufacturer_number=row.get("manufacturer_number"),
70
+ unit_price=row.get("unit_price"),
71
+ currency=row.get("currency")
72
+ )
73
+ parts.append(part)
74
+
75
+ self.session.add_all(parts)
76
+ self.session.commit()
77
+ print(f"Imported {len(parts)} parts successfully from {file_path}")
78
+
79
+ def total_value(self):
80
+ from decimal import Decimal
81
+ all_parts = self.session.query(Part).all()
82
+
83
+ total_value = Decimal(0.0)
84
+ for part in all_parts:
85
+ total_value = Decimal(total_value) + (Decimal(part.unit_price) * part.quantity)
86
+
87
+ return total_value
@@ -0,0 +1,71 @@
1
+ from sqlalchemy import Column, Integer, String, Float, DateTime, Numeric, Enum
2
+ from sqlalchemy.orm import DeclarativeBase
3
+ from datetime import datetime
4
+
5
+ import uuid
6
+
7
+ class Base(DeclarativeBase):
8
+ pass
9
+
10
+ class Part(Base):
11
+ __tablename__ = 'parts'
12
+
13
+ id = Column(Integer, primary_key=True)
14
+ uuid = Column(String(32), unique=True, nullable=False, default=str(uuid.uuid4()))
15
+ number = Column(String(50), nullable=False)
16
+ name = Column(String(200), nullable=False)
17
+ description = Column(String(1000), default="No description")
18
+ revision = Column(String(10), default="1")
19
+ lifecycle_state = Column(String(50), default="In Work")
20
+ owner = Column(String(100), default="system")
21
+ date_created = Column(DateTime, default=datetime.utcnow)
22
+ date_modified = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
23
+ material = Column(String(100))
24
+ mass = Column(Float)
25
+ dimension_x = Column(Float)
26
+ dimension_y = Column(Float)
27
+ dimension_z = Column(Float)
28
+ quantity = Column(Integer, default=0)
29
+ cad_reference = Column(String(200))
30
+ attached_documents_reference = Column(String(200))
31
+ lead_time = Column(Integer)
32
+ make_or_buy = Column(Enum('make', 'buy', name='make_or_buy_enum'))
33
+ supplier = Column(String(100))
34
+ manufacturer_number = Column(String(100))
35
+ unit_price = Column(Numeric(10, 2))
36
+ currency = Column(String(3))
37
+
38
+ def __repr__(self):
39
+ return f"<Part(id={self.id}, number={self.number}, name={self.name})>"
40
+
41
+ def to_dict(self):
42
+ return {column.name: getattr(self, column.name) for column in self.__table__.columns}
43
+
44
+
45
+ class Supplier(Base):
46
+ __tablename__ = 'suppliers'
47
+
48
+ id = Column(Integer, primary_key=True)
49
+ uuid = Column(String(32), unique=True, nullable=False)
50
+ name = Column(String(200), nullable=False)
51
+ description = Column(String(1000))
52
+ date_created = Column(DateTime, default=datetime.utcnow)
53
+ date_modified = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
54
+
55
+ class File(Base):
56
+ __tablename__ = 'files'
57
+
58
+ id = Column(Integer, primary_key=True)
59
+ uuid = Column(String(32), unique=True, nullable=False)
60
+ name = Column(String(200), nullable=False)
61
+ description = Column(String(1000))
62
+ date_created = Column(DateTime, default=datetime.utcnow)
63
+ date_modified = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
64
+
65
+ class NumberRange(Base):
66
+ __tablename__ = 'number_ranges'
67
+
68
+ id = Column(Integer, primary_key=True)
69
+ name = Column(String(200), nullable=False)
70
+ description = Column(String(1000))
71
+ date_created = Column(DateTime, default=datetime.utcnow)
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,20 @@
1
+ from setuptools import setup
2
+
3
+ setup(
4
+ name='OpenPartsLibrary',
5
+ version='0.1.0',
6
+ description='Python library for creating a database of hardware components for manufacturing',
7
+ url='https://github.com/alekssadowski95/OpenPartsLibrary',
8
+ author='Aleksander Sadowski',
9
+ author_email='aleksander.sadowski@alsado.de',
10
+ license='MIT',
11
+ packages=['openpartslibrary'],
12
+ install_requires=[''],
13
+
14
+ classifiers=[
15
+ 'Development Status :: 1 - Planning',
16
+ 'Intended Audience :: Science/Research',
17
+ 'License :: OSI Approved :: MIT License',
18
+ 'Programming Language :: Python :: 3'
19
+ ],
20
+ )