Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
Q
quality-kpi
Manage
Activity
Members
Labels
Plan
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Quiring, Ole
quality-kpi
Commits
41cbe8fd
Commit
41cbe8fd
authored
2 years ago
by
Hock, Benedikt
Browse files
Options
Downloads
Patches
Plain Diff
Checked some TODOs
parent
ef0fc4d4
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
functions/lego_classes.py
+150
-55
150 additions, 55 deletions
functions/lego_classes.py
with
150 additions
and
55 deletions
functions/lego_classes.py
+
150
−
55
View file @
41cbe8fd
...
...
@@ -2,97 +2,192 @@
File consists of several classes for the different elements of a device.
'''
from
__future__
import
annotations
from
enum
import
Enum
,
auto
import
uuid
from
typing
import
Any
,
Union
,
Literal
,
TypedDict
,
TypeVar
,
Type
,
List
,
Optional
,
Dict
import
json
# TODO
# - Parents direkt setzen
# - Alle gemeinsamen JSON attribute im LegoItem constructor
# - enforce uuid
# - Docstrings
# - Beschreibung von Teilen (-> properties)
# - Gute String Darstellung
# - Minimalbeispiel für KPIs
# - Klassen analog zur deutschen Aufgabenstellung umbenennen (assembly, component) #13 #17
# - Export als JSON
# - Export als GraphViz
# - AggregationsEbene enum (system, assembly, subassembly, component)
class
LegoItem
:
def
__init__
(
self
,
item_number
:
int
,
mass
:
float
,
delivery_time
:
int
,
**
kwargs
)
->
None
:
# , *args, **kwargs not handling additional/optional specs right now
self
.
id
:
uuid
.
UUID
=
uuid
.
uuid4
()
self
.
properties
:
dict
=
kwargs
self
.
item_number
:
int
=
item_number
class
ComponentCategory
(
Enum
):
BATTERY
=
auto
()
MOTOR
=
auto
()
FRAME
=
auto
()
WHEEL
=
auto
()
AXLE
=
auto
()
GEAR
=
auto
()
class
AggregationLayer
(
Enum
):
SYSTEM
=
auto
()
ASSEMBLY
=
auto
()
SUBASSEMBLY
=
auto
()
COMPONENT
=
auto
()
class
LegoComponent
:
def
__init__
(
self
,
name
:
str
,
category
:
ComponentCategory
,
lego_id
:
str
,
cost
:
float
,
mass
:
float
,
delivery_time
:
int
,
layer
:
AggregationLayer
=
AggregationLayer
.
COMPONENT
,
**
properties
)
->
None
:
self
.
uuid
:
uuid
.
UUID
=
uuid
.
uuid4
()
self
.
parent
:
None
|
LegoAssembly
=
None
self
.
name
:
str
=
name
self
.
category
:
ComponentCategory
=
category
self
.
lego_id
:
str
=
lego_id
self
.
cost
:
float
=
cost
self
.
mass
:
float
=
mass
self
.
delivery_time
:
int
=
delivery_time
# TODO: Set parent directly and not via id? This would allow for easier traversal of the tree
# Currently there is no way to search for parts and components in tree by id.
self
.
parent_id
=
None
# This will be set when added to a component
self
.
layer
:
AggregationLayer
=
layer
self
.
properties
:
dict
=
properties
def
clone
(
self
)
->
LegoComponent
:
clone
=
LegoComponent
(
self
.
name
,
self
.
category
,
self
.
lego_id
,
self
.
cost
,
self
.
mass
,
self
.
delivery_time
,
self
.
layer
,
**
self
.
properties
)
return
clone
def
get_root_assembly
(
self
):
if
self
.
parent
is
None
:
return
None
current_assembly
=
self
.
parent
while
current_assembly
.
parent
is
not
None
:
current_assembly
=
current_assembly
.
parent
return
current_assembly
def
to_dict
(
self
)
->
Dict
:
ATTRIBUTES
=
[
"
uuid
"
,
"
name
"
,
"
category
"
,
"
lego_id
"
,
"
cost
"
,
"
mass
"
,
"
delivery_time
"
,
"
layer
"
,
"
properties
"
]
dict_
=
{}
# store attributes
for
attr
in
ATTRIBUTES
:
dict_
[
attr
]
=
getattr
(
self
,
attr
)
dict_
=
{
"
component
"
:
dict_
}
return
dict_
# TODO good string representation
def
__str__
(
self
):
return
self
.
__repr__
()
return
(
f
"
Item(id=
{
self
.
id
}
, item_number=
{
self
.
item_number
}
,
"
f
"
Item(id=
{
self
.
uu
id
}
, item_number=
{
self
.
lego_id
}
,
"
f
"
mass=
{
self
.
mass
}
, delivery_time=
{
self
.
delivery_time
}
,
"
f
"
parent_id=
{
self
.
parent
_id
}
)
"
f
"
parent_id=
{
self
.
parent
}
)
"
)
# TODO good repr representation
def
__repr__
(
self
):
return
f
"
Lego
Item
[
{
self
.
id
}
]
"
return
f
"
Lego
Component
{
self
.
name
}
[
{
self
.
uu
id
}
]
"
class
LegoComponent
:
def
__init__
(
self
,
**
kwargs
)
->
None
:
self
.
id
:
uuid
.
UUID
=
uuid
.
uuid4
()
self
.
properties
:
dict
=
kwargs
self
.
items
:
List
[
LegoItem
]
=
[]
class
LegoAssembly
:
def
__init__
(
self
,
name
:
str
,
layer
:
AggregationLayer
,
**
properties
)
->
None
:
self
.
uuid
:
uuid
.
UUID
=
uuid
.
uuid4
()
self
.
parent
:
None
|
LegoAssembly
=
None
self
.
name
:
str
=
name
self
.
layer
:
AggregationLayer
=
layer
self
.
properties
:
dict
=
properties
self
.
components
:
List
[
LegoComponent
]
=
[]
self
.
parent_id
:
None
|
uuid
.
UUID
=
None
def
add_item
(
self
,
item
:
LegoItem
)
->
None
:
if
not
isinstance
(
item
,
LegoItem
):
raise
TypeError
(
f
"'
item
'
should be of type LegoPart, got
{
type
(
item
).
__name__
}
instead.
"
)
item
.
parent_id
=
self
.
id
self
.
items
.
append
(
item
)
self
.
assemblies
:
List
[
LegoAssembly
]
=
[]
def
add_component
(
self
,
component
:
LegoComponent
)
->
None
:
if
not
isinstance
(
component
,
LegoComponent
):
raise
TypeError
(
f
"'
component
'
should be of type LegoComponent, got
{
type
(
component
).
__name__
}
instead.
"
)
component
.
parent_id
=
self
.
id
raise
TypeError
(
f
"
Argument should be of type
{
LegoComponent
.
__name__
}
,
"
f
"
got
{
type
(
component
).
__name__
}
instead.
"
)
if
self
.
get_root_assembly
().
contains_uuid
(
component
.
uuid
):
raise
AssertionError
(
f
"
This assembly or a subassembly already contains the component with ID
"
f
"
{
component
.
uuid
}
.
"
)
component
.
parent
=
self
self
.
components
.
append
(
component
)
def
children
(
self
)
->
Dict
[
str
,
List
[
LegoItem
]
|
List
[
LegoComponent
]]:
return
{
'
items
'
:
self
.
items
,
'
components
'
:
self
.
components
}
def
add_assembly
(
self
,
assembly
:
LegoAssembly
)
->
None
:
if
not
isinstance
(
assembly
,
LegoAssembly
):
raise
TypeError
(
f
"
Argument should be of type
{
LegoAssembly
.
__name__
}
,
"
f
"
got
{
type
(
assembly
).
__name__
}
instead.
"
)
if
self
.
get_root_assembly
().
contains_uuid
(
assembly
.
uuid
):
raise
AssertionError
(
f
"
This assembly or a subassembly already contains the assembly with ID
"
f
"
{
assembly
.
uuid
}
.
"
)
assembly
.
parent
=
self
self
.
assemblies
.
append
(
assembly
)
def
children
(
self
)
->
Dict
[
str
,
List
[
LegoComponent
]
|
List
[
LegoAssembly
]]:
return
{
'
components
'
:
self
.
components
,
'
assemblies
'
:
self
.
assemblies
}
def
get_component_list
(
self
,
max_depth
:
int
=
-
1
)
->
List
[
LegoComponent
]:
component_list
=
[]
component_list
.
extend
(
self
.
components
)
if
max_depth
>
0
:
for
assembly
in
self
.
assemblies
:
component_list
.
extend
(
assembly
.
get_component_list
(
max_depth
-
1
))
return
component_list
def
get_item_list
(
self
)
->
List
[
LegoItem
]:
item_list
=
[]
item_list
.
extend
(
self
.
items
)
for
component
in
self
.
components
:
item_list
.
extend
(
component
.
get_item_list
())
return
item_list
def
get_root_assembly
(
self
)
->
LegoAssembly
:
current_assembly
=
self
while
current_assembly
.
parent
is
not
None
:
current_assembly
=
current_assembly
.
parent
return
current_assembly
def
contains_uuid
(
self
,
uuid_
:
uuid
.
UUID
):
# check component ids
component_ids
=
list
(
map
(
lambda
c
:
c
.
uuid
,
self
.
components
))
if
uuid_
in
component_ids
:
return
True
# check assembly ids
assembly_ids
=
list
(
map
(
lambda
a
:
a
.
uuid
,
self
.
assemblies
))
if
uuid_
in
assembly_ids
:
return
True
# recursively check assemblies
for
assembly
in
self
.
assemblies
:
if
assembly
.
contains_uuid
(
uuid_
):
return
True
return
False
def
to_dict
(
self
)
->
Dict
:
ATTRIBUTES
=
[
"
uuid
"
,
"
name
"
,
"
layer
"
,
"
properties
"
]
dict_
=
{}
# store attributes
for
attr
in
ATTRIBUTES
:
dict_
[
attr
]
=
getattr
(
self
,
attr
)
# store components
dict_
[
"
components
"
]
=
[
component
.
to_dict
()
for
component
in
self
.
components
]
dict_
[
"
assemblies
"
]
=
[
assembly
.
to_dict
()
for
assembly
in
self
.
assemblies
]
return
{
"
assembly
"
:
dict_
}
# TODO find good string representation
def
__repr__
(
self
):
return
f
"
Lego
Component
[
{
self
.
id
}
]
"
return
f
"
Lego
Assembly
{
self
.
name
}
[
{
self
.
uu
id
}
]
"
# TODO: Adjust default output when printing an item or component
def
print_
component
_tree
(
root
,
level
=
0
,
is_last
=
False
):
def
print_
assembly
_tree
(
root
,
level
=
0
,
is_last
=
False
):
# print component
component
_padding
=
""
assembly
_padding
=
""
if
level
>
0
:
component
_padding
+=
"
│
"
*
(
level
-
1
)
assembly
_padding
+=
"
│
"
*
(
level
-
1
)
if
is_last
:
component
_padding
+=
"
└──
"
assembly
_padding
+=
"
└──
"
else
:
component
_padding
+=
"
├──
"
print
(
f
"
{
component
_padding
}{
root
}
"
)
assembly
_padding
+=
"
├──
"
print
(
f
"
{
assembly
_padding
}{
root
}
"
)
# recursively print child components
for
i
,
component
in
enumerate
(
root
.
component
s
):
is_last_
=
i
==
len
(
root
.
component
s
)
-
1
and
len
(
root
.
item
s
)
==
0
print_
component_tree
(
component
,
level
+
1
,
is_last_
)
for
i
,
assembly
in
enumerate
(
root
.
assemblie
s
):
is_last_
=
i
==
len
(
root
.
assemblie
s
)
-
1
and
len
(
root
.
component
s
)
==
0
print_
assembly_tree
(
assembly
,
level
+
1
,
is_last_
)
# print items
for
i
,
item
in
enumerate
(
root
.
items
):
item_padding
=
"
│
"
*
level
item_padding
+=
"
├──
"
if
i
<
len
(
root
.
items
)
-
1
else
"
└──
"
print
(
f
"
{
item_padding
}{
item
}
"
)
for
i
,
item
in
enumerate
(
root
.
components
):
component_padding
=
"
│
"
*
level
if
not
is_last
else
"
"
component_padding
+=
"
├──
"
if
i
<
len
(
root
.
components
)
-
1
else
"
└──
"
print
(
f
"
{
component_padding
}{
item
}
"
)
class
KPIEncoder
(
json
.
JSONEncoder
):
def
default
(
self
,
o
):
if
isinstance
(
o
,
uuid
.
UUID
):
return
"
kpi-
"
+
str
(
o
)
if
isinstance
(
o
,
(
ComponentCategory
,
AggregationLayer
)):
return
"
kpi-
"
+
o
.
name
return
super
().
default
(
o
)
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment