partcad-cli 0.5.22__tar.gz → 0.6.2__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.
Files changed (22) hide show
  1. {partcad_cli-0.5.22 → partcad_cli-0.6.2}/PKG-INFO +12 -4
  2. {partcad_cli-0.5.22 → partcad_cli-0.6.2}/README.md +10 -2
  3. {partcad_cli-0.5.22 → partcad_cli-0.6.2}/pyproject.toml +1 -1
  4. {partcad_cli-0.5.22 → partcad_cli-0.6.2}/requirements.txt +1 -1
  5. {partcad_cli-0.5.22 → partcad_cli-0.6.2}/src/partcad_cli/__init__.py +1 -1
  6. {partcad_cli-0.5.22 → partcad_cli-0.6.2}/src/partcad_cli/cli.py +32 -3
  7. {partcad_cli-0.5.22 → partcad_cli-0.6.2}/src/partcad_cli/cli_add.py +21 -1
  8. {partcad_cli-0.5.22 → partcad_cli-0.6.2}/src/partcad_cli/cli_info.py +16 -0
  9. {partcad_cli-0.5.22 → partcad_cli-0.6.2}/src/partcad_cli/cli_inspect.py +25 -3
  10. partcad_cli-0.6.2/src/partcad_cli/cli_list.py +525 -0
  11. {partcad_cli-0.5.22 → partcad_cli-0.6.2}/src/partcad_cli/cli_status.py +3 -0
  12. {partcad_cli-0.5.22 → partcad_cli-0.6.2}/src/partcad_cli.egg-info/PKG-INFO +12 -4
  13. {partcad_cli-0.5.22 → partcad_cli-0.6.2}/src/partcad_cli.egg-info/requires.txt +1 -1
  14. partcad_cli-0.5.22/src/partcad_cli/cli_list.py +0 -245
  15. {partcad_cli-0.5.22 → partcad_cli-0.6.2}/setup.cfg +0 -0
  16. {partcad_cli-0.5.22 → partcad_cli-0.6.2}/src/partcad_cli/cli_init.py +0 -0
  17. {partcad_cli-0.5.22 → partcad_cli-0.6.2}/src/partcad_cli/cli_install.py +0 -0
  18. {partcad_cli-0.5.22 → partcad_cli-0.6.2}/src/partcad_cli/cli_render.py +0 -0
  19. {partcad_cli-0.5.22 → partcad_cli-0.6.2}/src/partcad_cli.egg-info/SOURCES.txt +0 -0
  20. {partcad_cli-0.5.22 → partcad_cli-0.6.2}/src/partcad_cli.egg-info/dependency_links.txt +0 -0
  21. {partcad_cli-0.5.22 → partcad_cli-0.6.2}/src/partcad_cli.egg-info/entry_points.txt +0 -0
  22. {partcad_cli-0.5.22 → partcad_cli-0.6.2}/src/partcad_cli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: partcad-cli
3
- Version: 0.5.22
3
+ Version: 0.6.2
4
4
  Summary: Command-line interface to PartCAD
5
5
  Author-email: Roman Kuzmenko <openvmp@proton.me>
6
6
  Maintainer-email: Roman Kuzmenko <openvmp@proton.me>
@@ -12,7 +12,7 @@ Classifier: License :: OSI Approved :: Apache Software License
12
12
  Classifier: Operating System :: OS Independent
13
13
  Requires-Python: >=3.10
14
14
  Description-Content-Type: text/markdown
15
- Requires-Dist: partcad==0.5.22
15
+ Requires-Dist: partcad==0.6.2
16
16
  Requires-Dist: renderlab
17
17
  Requires-Dist: rlPyCairo
18
18
  Requires-Dist: svglib
@@ -30,14 +30,22 @@ Requires-Dist: ocp_vscode
30
30
 
31
31
  PartCAD is the first package manager for CAD models
32
32
  and a framework for managing assemblies.
33
- It complements Git with everything necessary to substitute
33
+ It aims to complement Git with everything necessary to substitute
34
34
  commercial Product Lifecycle Management (PLM) tools.
35
35
 
36
36
  PartCAD maintains information about mechanical parts and
37
37
  how they come together to form larger assemblies.
38
- The same parts are reused in multiple assemblies and multiple projects.
38
+ The same parts can be reused in multiple assemblies and multiple projects.
39
39
  And all of that is supercharged by the ultimate versioning and collaboration features of Git.
40
40
 
41
+ PartCAD features include:
42
+
43
+ - 3D part models using STEP, STL and 3MF files
44
+ - 3D part models using CadQuery, build123d and OpenSCAD scripting languages (including AI-generated: Gemini and GPT)
45
+ - 2D blueprints using DXF, build123d and SVG files
46
+ - Fully featured object-oriented approach to maintain part interfaces and mating information (with multiple class inheritance etc)
47
+ - Live preview of 3D models while coding in VS Code
48
+
41
49
  Find [more documentation here](https://partcad.readthedocs.io/en/latest/?badge=latest) and visit [our website](https://partcad.org/).
42
50
 
43
51
  ## Installation
@@ -10,14 +10,22 @@
10
10
 
11
11
  PartCAD is the first package manager for CAD models
12
12
  and a framework for managing assemblies.
13
- It complements Git with everything necessary to substitute
13
+ It aims to complement Git with everything necessary to substitute
14
14
  commercial Product Lifecycle Management (PLM) tools.
15
15
 
16
16
  PartCAD maintains information about mechanical parts and
17
17
  how they come together to form larger assemblies.
18
- The same parts are reused in multiple assemblies and multiple projects.
18
+ The same parts can be reused in multiple assemblies and multiple projects.
19
19
  And all of that is supercharged by the ultimate versioning and collaboration features of Git.
20
20
 
21
+ PartCAD features include:
22
+
23
+ - 3D part models using STEP, STL and 3MF files
24
+ - 3D part models using CadQuery, build123d and OpenSCAD scripting languages (including AI-generated: Gemini and GPT)
25
+ - 2D blueprints using DXF, build123d and SVG files
26
+ - Fully featured object-oriented approach to maintain part interfaces and mating information (with multiple class inheritance etc)
27
+ - Live preview of 3D models while coding in VS Code
28
+
21
29
  Find [more documentation here](https://partcad.readthedocs.io/en/latest/?badge=latest) and visit [our website](https://partcad.org/).
22
30
 
23
31
  ## Installation
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "partcad-cli"
3
- version = "0.5.22"
3
+ version = "0.6.2"
4
4
  description = "Command-line interface to PartCAD"
5
5
  readme = "README.md"
6
6
  keywords = ["cadquery", "build123d", "cad", "design", "openscad", "step", "stl"]
@@ -1,4 +1,4 @@
1
- partcad==0.5.22
1
+ partcad==0.6.2
2
2
  renderlab
3
3
  rlPyCairo
4
4
  svglib
@@ -4,4 +4,4 @@ __all__ = [
4
4
  "main_cli",
5
5
  ]
6
6
 
7
- __version__: str = "0.5.22"
7
+ __version__: str = "0.6.2"
@@ -40,6 +40,13 @@ def main():
40
40
  action="count",
41
41
  default=0,
42
42
  )
43
+ parser.add_argument(
44
+ "-q",
45
+ help="Decrease the level of verbosity",
46
+ dest="quiet",
47
+ action="count",
48
+ default=0,
49
+ )
43
50
  parser.add_argument(
44
51
  "--no-ansi",
45
52
  help="Plain logging output. Do not use colors or animations.",
@@ -55,6 +62,10 @@ def main():
55
62
  )
56
63
  # TODO(clairbee): add a config option to change logging mechanism and level
57
64
  subparsers = parser.add_subparsers(dest="command")
65
+ subparsers.add_parser(
66
+ "version",
67
+ help="Print PartCAD version and exit",
68
+ )
58
69
  cli_help_add(subparsers)
59
70
  cli_help_init(subparsers)
60
71
  cli_help_info(subparsers)
@@ -72,10 +83,13 @@ def main():
72
83
  else:
73
84
  logging.basicConfig()
74
85
 
75
- if args.verbosity > 0:
76
- pc.logging.setLevel(logging.DEBUG)
86
+ if args.quiet > 0:
87
+ pc.logging.setLevel(logging.ERROR)
77
88
  else:
78
- pc.logging.setLevel(logging.INFO)
89
+ if args.verbosity > 0:
90
+ pc.logging.setLevel(logging.DEBUG)
91
+ else:
92
+ pc.logging.setLevel(logging.INFO)
79
93
 
80
94
  try:
81
95
  # First, handle the commands that don't require a context or initialize it
@@ -86,6 +100,9 @@ def main():
86
100
  elif args.command == "status":
87
101
  cli_status(args)
88
102
  return
103
+ elif args.command == "version":
104
+ pc_logging.info("PartCAD version: %s" % pc.__version__)
105
+ return
89
106
 
90
107
  if args.command == "install" or args.command == "update":
91
108
  user_config.force_update = True
@@ -126,6 +143,18 @@ def main():
126
143
  cli_list_assemblies(args, ctx)
127
144
  cli_list_parts(args, ctx)
128
145
 
146
+ elif args.command == "list-sketches":
147
+ with pc_logging.Process("ListSketches", "this"):
148
+ cli_list_sketches(args, ctx)
149
+
150
+ elif args.command == "list-interfaces":
151
+ with pc_logging.Process("ListInterfaces", "this"):
152
+ cli_list_interfaces(args, ctx)
153
+
154
+ elif args.command == "list-mates":
155
+ with pc_logging.Process("ListMates", "this"):
156
+ cli_list_mates(args, ctx)
157
+
129
158
  elif args.command == "list-parts":
130
159
  with pc_logging.Process("ListParts", "this"):
131
160
  cli_list_parts(args, ctx)
@@ -33,6 +33,21 @@ def cli_help_add(subparsers):
33
33
  "add-part",
34
34
  help="Add a part",
35
35
  )
36
+ parser_add_part.add_argument(
37
+ "--desc",
38
+ help="The part description (also used by LLMs).",
39
+ dest="desc",
40
+ type=str,
41
+ required=False,
42
+ )
43
+ parser_add_part.add_argument(
44
+ "--ai",
45
+ help="Generative AI provider.",
46
+ dest="provider",
47
+ type=str,
48
+ choices=["google", "openai"],
49
+ required=False,
50
+ )
36
51
  parser_add_part.add_argument(
37
52
  "kind",
38
53
  help="Type of the part",
@@ -78,7 +93,12 @@ def cli_add(args, ctx):
78
93
 
79
94
  def cli_add_part(args, ctx):
80
95
  prj = ctx.get_project(pc.ROOT)
81
- if prj.add_part(args.kind, args.path):
96
+ config = {}
97
+ if args.desc:
98
+ config["desc"] = args.desc
99
+ if args.provider:
100
+ config["provider"] = args.provider
101
+ if prj.add_part(args.kind, args.path, config):
82
102
  Path(args.path).touch()
83
103
 
84
104
 
@@ -29,6 +29,12 @@ def cli_help_info(subparsers):
29
29
  )
30
30
 
31
31
  group_type = parser_info.add_mutually_exclusive_group(required=False)
32
+ group_type.add_argument(
33
+ "-i",
34
+ help="The object is an interface",
35
+ dest="interface",
36
+ action="store_true",
37
+ )
32
38
  group_type.add_argument(
33
39
  "-a",
34
40
  help="The object is an assembly",
@@ -37,6 +43,12 @@ def cli_help_info(subparsers):
37
43
  )
38
44
  group_type.add_argument(
39
45
  "-s",
46
+ help="The object is a sketch",
47
+ dest="sketch",
48
+ action="store_true",
49
+ )
50
+ group_type.add_argument(
51
+ "-S",
40
52
  help="The object is a scene",
41
53
  dest="scene",
42
54
  action="store_true",
@@ -75,6 +87,10 @@ def cli_info(args, ctx):
75
87
 
76
88
  if args.assembly:
77
89
  obj = ctx.get_assembly(path, params=params)
90
+ elif args.interface:
91
+ obj = ctx.get_interface(path)
92
+ elif args.sketch:
93
+ obj = ctx.get_sketch(path, params=params)
78
94
  else:
79
95
  obj = ctx.get_part(path, params=params)
80
96
 
@@ -35,6 +35,12 @@ def cli_help_inspect(subparsers):
35
35
  )
36
36
 
37
37
  group_type = parser_inspect.add_mutually_exclusive_group(required=False)
38
+ group_type.add_argument(
39
+ "-i",
40
+ help="The object is an interface",
41
+ dest="interface",
42
+ action="store_true",
43
+ )
38
44
  group_type.add_argument(
39
45
  "-a",
40
46
  help="The object is an assembly",
@@ -43,6 +49,12 @@ def cli_help_inspect(subparsers):
43
49
  )
44
50
  group_type.add_argument(
45
51
  "-s",
52
+ help="The object is a sketch",
53
+ dest="sketch",
54
+ action="store_true",
55
+ )
56
+ group_type.add_argument(
57
+ "-S",
46
58
  help="The object is a scene",
47
59
  dest="scene",
48
60
  action="store_true",
@@ -81,6 +93,10 @@ def cli_inspect(args, ctx):
81
93
 
82
94
  if args.assembly:
83
95
  obj = ctx.get_assembly(path, params=params)
96
+ elif args.interface:
97
+ obj = ctx.get_interface(path)
98
+ elif args.sketch:
99
+ obj = ctx.get_sketch(path, params=params)
84
100
  else:
85
101
  obj = ctx.get_part(path, params=params)
86
102
 
@@ -94,8 +110,14 @@ def cli_inspect(args, ctx):
94
110
  )
95
111
  else:
96
112
  if args.verbal:
97
- pc_logging.info(
98
- "Summary: %s" % obj.get_summary(project=args.package)
99
- )
113
+ if args.package is None:
114
+ package_obj = ctx.get_project("/")
115
+ else:
116
+ package_obj = ctx.get_project(args.package)
117
+
118
+ summary = obj.get_summary(package_obj)
119
+ pc_logging.info("Summary: %s" % summary)
120
+ if args.quiet > 0:
121
+ print("%s" % summary)
100
122
  else:
101
123
  obj.show()
@@ -0,0 +1,525 @@
1
+ #
2
+ # OpenVMP, 2023
3
+ #
4
+ # Author: Roman Kuzmenko
5
+ # Created: 2023-12-23
6
+ #
7
+ # Licensed under Apache License, Version 2.0.
8
+ #
9
+
10
+ import time
11
+
12
+ import partcad as pc
13
+
14
+
15
+ def cli_help_list(subparsers):
16
+ parser_list = subparsers.add_parser(
17
+ "list",
18
+ help="List imported packages",
19
+ )
20
+ parser_list_all = subparsers.add_parser(
21
+ "list-all",
22
+ help="List available parts, assemblies and scenes",
23
+ )
24
+ parser_list_sketches = subparsers.add_parser(
25
+ "list-sketches",
26
+ help="List available sketches",
27
+ )
28
+ parser_list_interfaces = subparsers.add_parser(
29
+ "list-interfaces",
30
+ help="List available interfaces",
31
+ )
32
+ parser_list_mates = subparsers.add_parser(
33
+ "list-mates",
34
+ help="List available mating interfaces",
35
+ )
36
+ parser_list_parts = subparsers.add_parser(
37
+ "list-parts",
38
+ help="List available parts",
39
+ )
40
+ parser_list_assemblies = subparsers.add_parser(
41
+ "list-assemblies",
42
+ help="List available assemblies",
43
+ )
44
+
45
+ parser_list_all.add_argument(
46
+ "-r",
47
+ help="Recursively process all imported packages",
48
+ dest="recursive",
49
+ action="store_true",
50
+ )
51
+ parser_list_sketches.add_argument(
52
+ "-r",
53
+ help="Recursively process all imported packages",
54
+ dest="recursive",
55
+ action="store_true",
56
+ )
57
+ parser_list_interfaces.add_argument(
58
+ "-r",
59
+ help="Recursively process all imported packages",
60
+ dest="recursive",
61
+ action="store_true",
62
+ )
63
+ parser_list_mates.add_argument(
64
+ "-r",
65
+ help="Recursively process all imported packages",
66
+ dest="recursive",
67
+ action="store_true",
68
+ )
69
+ parser_list_parts.add_argument(
70
+ "-r",
71
+ help="Recursively process all imported packages",
72
+ dest="recursive",
73
+ action="store_true",
74
+ )
75
+ parser_list_assemblies.add_argument(
76
+ "-r",
77
+ help="Recursively process all imported packages",
78
+ dest="recursive",
79
+ action="store_true",
80
+ )
81
+
82
+ parser_list_all.add_argument(
83
+ "-u",
84
+ help="Only process objects used by the given assembly or scene.",
85
+ dest="used_by",
86
+ type=str,
87
+ required=False,
88
+ )
89
+ parser_list_sketches.add_argument(
90
+ "-u",
91
+ help="Only process objects used by the given assembly or scene.",
92
+ dest="used_by",
93
+ type=str,
94
+ required=False,
95
+ )
96
+ parser_list_interfaces.add_argument(
97
+ "-u",
98
+ help="Only process objects used by the given assembly or scene.",
99
+ dest="used_by",
100
+ type=str,
101
+ required=False,
102
+ )
103
+ parser_list_mates.add_argument(
104
+ "-u",
105
+ help="Only process objects used by the given assembly or scene.",
106
+ dest="used_by",
107
+ type=str,
108
+ required=False,
109
+ )
110
+ parser_list_parts.add_argument(
111
+ "-u",
112
+ help="Only process objects used by the given assembly or scene.",
113
+ dest="used_by",
114
+ type=str,
115
+ required=False,
116
+ )
117
+ parser_list_assemblies.add_argument(
118
+ "-u",
119
+ help="Only process objects used by the given assembly or scene.",
120
+ dest="used_by",
121
+ type=str,
122
+ required=False,
123
+ )
124
+
125
+ parser_list_sketches.add_argument(
126
+ "package",
127
+ help="Package to retrieve the object from",
128
+ type=str,
129
+ nargs="?",
130
+ )
131
+ parser_list_interfaces.add_argument(
132
+ "package",
133
+ help="Package to retrieve the object from",
134
+ type=str,
135
+ nargs="?",
136
+ )
137
+ parser_list_mates.add_argument(
138
+ "package",
139
+ help="Package to retrieve the object from",
140
+ type=str,
141
+ nargs="?",
142
+ )
143
+ parser_list_parts.add_argument(
144
+ "package",
145
+ help="Package to retrieve the object from",
146
+ type=str,
147
+ nargs="?",
148
+ )
149
+ parser_list_assemblies.add_argument(
150
+ "package",
151
+ help="Package to retrieve the object from",
152
+ type=str,
153
+ nargs="?",
154
+ )
155
+
156
+
157
+ def cli_list(args, ctx):
158
+ pkg_count = 0
159
+
160
+ projects = ctx.get_all_packages()
161
+ projects = sorted(projects, key=lambda p: p["name"])
162
+
163
+ # TODO(clairbee): remove the following workaround after replacing 'print'
164
+ # with corresponding logging calls
165
+ time.sleep(2)
166
+
167
+ output = "PartCAD packages:\n"
168
+ for project in projects:
169
+ project_name = project["name"]
170
+
171
+ line = "\t%s" % project_name
172
+ padding_size = 60 - len(project_name)
173
+ if padding_size < 4:
174
+ padding_size = 4
175
+ line += " " * padding_size
176
+ line += "%s" % project["desc"]
177
+ output += line + "\n"
178
+ pkg_count = pkg_count + 1
179
+
180
+ if pkg_count < 1:
181
+ output += "\t<none>\n"
182
+ pc.logging.info(output)
183
+
184
+
185
+ def cli_list_sketches(args, ctx):
186
+ sketch_count = 0
187
+ sketch_kinds = 0
188
+
189
+ if args.used_by is not None:
190
+ pc.logging.info("Instantiating %s..." % args.used_by)
191
+ ctx.get_assembly(args.used_by)
192
+ else:
193
+ ctx.get_all_packages()
194
+
195
+ # TODO(clairbee): remove the following workaround after replacing 'print'
196
+ # with corresponding logging calls
197
+ time.sleep(2)
198
+
199
+ output = "PartCAD sketches:\n"
200
+ for project_name in ctx.projects:
201
+ if (
202
+ hasattr(args, "package")
203
+ and not args.package is None
204
+ and args.package != project_name
205
+ ):
206
+ continue
207
+
208
+ if project_name != ctx.get_current_project_path() and (
209
+ not args.recursive
210
+ and hasattr(args, "package")
211
+ and args.package is None
212
+ ):
213
+ continue
214
+
215
+ project = ctx.projects[project_name]
216
+
217
+ for sketch_name, sketch in project.sketches.items():
218
+ if args.used_by is not None and sketch.count == 0:
219
+ continue
220
+
221
+ line = "\t"
222
+ if args.recursive:
223
+ line += "%s" % project_name
224
+ line += " " + " " * (35 - len(project_name))
225
+ line += "%s" % sketch_name
226
+ if args.used_by is not None:
227
+ sketch = project.sketches[sketch_name]
228
+ line += "(%d)" % sketch.count
229
+ sketch_count = sketch_count + sketch.count
230
+ line += " " + " " * (35 - len(sketch_name))
231
+
232
+ desc = sketch.desc if sketch.desc is not None else ""
233
+ desc = desc.replace(
234
+ "\n", "\n" + " " * (80 if args.recursive else 44)
235
+ )
236
+ line += "%s" % desc
237
+ output += line + "\n"
238
+ sketch_kinds = sketch_kinds + 1
239
+
240
+ if sketch_kinds > 0:
241
+ if args.used_by is None:
242
+ output += "Total: %d\n" % sketch_kinds
243
+ else:
244
+ output += "Total: %d sketches of %d kinds\n" % (
245
+ sketch_count,
246
+ sketch_kinds,
247
+ )
248
+ else:
249
+ output += "\t<none>\n"
250
+ pc.logging.info(output)
251
+
252
+
253
+ def cli_list_interfaces(args, ctx):
254
+ interface_count = 0
255
+ interface_kinds = 0
256
+
257
+ if args.used_by is not None:
258
+ pc.logging.info("Instantiating %s..." % args.used_by)
259
+ ctx.get_assembly(args.used_by)
260
+ else:
261
+ ctx.get_all_packages()
262
+
263
+ # TODO(clairbee): remove the following workaround after replacing 'print'
264
+ # with corresponding logging calls
265
+ time.sleep(2)
266
+
267
+ output = "PartCAD interfaces:\n"
268
+ for project_name in ctx.projects:
269
+ if (
270
+ hasattr(args, "package")
271
+ and not args.package is None
272
+ and args.package != project_name
273
+ ):
274
+ continue
275
+
276
+ if project_name != ctx.get_current_project_path() and (
277
+ not args.recursive
278
+ and hasattr(args, "package")
279
+ and args.package is None
280
+ ):
281
+ continue
282
+
283
+ project = ctx.projects[project_name]
284
+
285
+ for interface_name, interface in project.interfaces.items():
286
+ if args.used_by is not None and interface.count == 0:
287
+ continue
288
+
289
+ line = "\t"
290
+ if args.recursive:
291
+ line += "%s" % project_name
292
+ line += " " + " " * (35 - len(project_name))
293
+ line += "%s" % interface_name
294
+ if args.used_by is not None:
295
+ interface = project.get_interface(interface_name)
296
+ line += "(%d)" % interface.count
297
+ interface_count = interface_count + interface.count
298
+ line += " " + " " * (35 - len(interface_name))
299
+
300
+ desc = interface.desc if interface.desc is not None else ""
301
+ desc = desc.replace(
302
+ "\n", "\n" + " " * (80 if args.recursive else 44)
303
+ )
304
+ line += "%s" % desc
305
+ output += line + "\n"
306
+ interface_kinds = interface_kinds + 1
307
+
308
+ if interface_kinds > 0:
309
+ if args.used_by is None:
310
+ output += "Total: %d\n" % interface_kinds
311
+ else:
312
+ output += "Total: %d interfaces of %d kinds\n" % (
313
+ interface_count,
314
+ interface_kinds,
315
+ )
316
+ else:
317
+ output += "\t<none>\n"
318
+ pc.logging.info(output)
319
+
320
+
321
+ def cli_list_mates(args, ctx):
322
+ mating_kinds = 0
323
+
324
+ if args.used_by is not None:
325
+ pc.logging.info("Instantiating %s..." % args.used_by)
326
+ ctx.get_assembly(args.used_by)
327
+ else:
328
+ ctx.get_all_packages()
329
+
330
+ # TODO(clairbee): remove the following workaround after replacing 'print'
331
+ # with corresponding logging calls
332
+ time.sleep(2)
333
+
334
+ output = "PartCAD mating interfaces:\n"
335
+ for source_interface_name in ctx.mates:
336
+ source_package_name = source_interface_name.split(":")[0]
337
+ short_source_interface_name = source_interface_name.split(":")[1]
338
+
339
+ for target_interface_name in ctx.mates[source_interface_name]:
340
+ target_package_name = target_interface_name.split(":")[0]
341
+ short_target_interface_name = target_interface_name.split(":")[1]
342
+
343
+ mating = ctx.mates[source_interface_name][target_interface_name]
344
+
345
+ if (
346
+ hasattr(args, "package")
347
+ and not args.package is None
348
+ and args.package != source_package_name
349
+ and args.package != target_package_name
350
+ ):
351
+ continue
352
+
353
+ if (
354
+ source_package_name != ctx.get_current_project_path()
355
+ and target_package_name != ctx.get_current_project_path()
356
+ and not args.recursive
357
+ and hasattr(args, "package")
358
+ and args.package is None
359
+ ):
360
+ continue
361
+
362
+ # source_project = ctx.projects[source_package_name]
363
+ # target_project = ctx.projects[target_package_name]
364
+
365
+ # source_interface = source_project.get_interface(
366
+ # short_source_interface_name
367
+ # )
368
+ # target_interface = target_project.get_interface(
369
+ # short_target_interface_name
370
+ # )
371
+
372
+ if args.used_by is not None and mating.count == 0:
373
+ continue
374
+
375
+ line = "\t"
376
+ line += "%s" % source_interface_name
377
+ line += " " + " " * (35 - len(source_interface_name))
378
+ line += "%s" % target_interface_name
379
+ line += " " + " " * (35 - len(target_interface_name))
380
+
381
+ desc = mating.desc if mating.desc is not None else ""
382
+ desc = desc.replace("\n", "\n\t" + " " * 72)
383
+ line += "%s" % desc
384
+ output += line + "\n"
385
+ mating_kinds = mating_kinds + 1
386
+
387
+ if mating_kinds > 0:
388
+ output += "Total: %d mating interfaces\n" % (mating_kinds,)
389
+ else:
390
+ output += "\t<none>\n"
391
+ pc.logging.info(output)
392
+
393
+
394
+ def cli_list_parts(args, ctx):
395
+ part_count = 0
396
+ part_kinds = 0
397
+
398
+ if args.used_by is not None:
399
+ pc.logging.info("Instantiating %s..." % args.used_by)
400
+ ctx.get_assembly(args.used_by)
401
+ else:
402
+ ctx.get_all_packages()
403
+
404
+ # TODO(clairbee): remove the following workaround after replacing 'print'
405
+ # with corresponding logging calls
406
+ time.sleep(2)
407
+
408
+ output = "PartCAD parts:\n"
409
+ for project_name in ctx.projects:
410
+ if (
411
+ hasattr(args, "package")
412
+ and not args.package is None
413
+ and args.package != project_name
414
+ ):
415
+ continue
416
+
417
+ if project_name != ctx.get_current_project_path() and (
418
+ not args.recursive
419
+ and hasattr(args, "package")
420
+ and args.package is None
421
+ ):
422
+ continue
423
+
424
+ project = ctx.projects[project_name]
425
+
426
+ for part_name, part in project.parts.items():
427
+ if args.used_by is not None and part.count == 0:
428
+ continue
429
+
430
+ line = "\t"
431
+ if args.recursive:
432
+ line += "%s" % project_name
433
+ line += " " + " " * (35 - len(project_name))
434
+ line += "%s" % part_name
435
+ if args.used_by is not None:
436
+ part = project.parts[part_name]
437
+ line += "(%d)" % part.count
438
+ part_count = part_count + part.count
439
+ line += " " + " " * (35 - len(part_name))
440
+
441
+ desc = part.desc if part.desc is not None else ""
442
+ desc = desc.replace(
443
+ "\n", "\n" + " " * (80 if args.recursive else 44)
444
+ )
445
+ line += "%s" % desc
446
+ output += line + "\n"
447
+ part_kinds = part_kinds + 1
448
+
449
+ if part_kinds > 0:
450
+ if args.used_by is None:
451
+ output += "Total: %d\n" % part_kinds
452
+ else:
453
+ output += "Total: %d parts of %d kinds\n" % (part_count, part_kinds)
454
+ else:
455
+ output += "\t<none>\n"
456
+ pc.logging.info(output)
457
+
458
+
459
+ def cli_list_assemblies(args, ctx):
460
+ assy_count = 0
461
+ assy_kinds = 0
462
+
463
+ if args.used_by is not None:
464
+ print("Instantiating %s..." % args.used_by)
465
+ # TODO(clairbee): do not call it twice in 'list-all'
466
+ ctx.get_assembly(args.used_by)
467
+ else:
468
+ ctx.get_all_packages()
469
+
470
+ # TODO(clairbee): remove the following workaround after replacing 'print'
471
+ # with corresponding logging calls
472
+ time.sleep(2)
473
+
474
+ output = "PartCAD assemblies:\n"
475
+ for project_name in ctx.projects:
476
+ if (
477
+ hasattr(args, "package")
478
+ and not args.package is None
479
+ and args.package != project_name
480
+ ):
481
+ continue
482
+
483
+ if project_name != ctx.get_current_project_path() and (
484
+ not args.recursive
485
+ and hasattr(args, "package")
486
+ and args.package is None
487
+ ):
488
+ continue
489
+
490
+ project = ctx.projects[project_name]
491
+
492
+ for assy_name, assy in project.assemblies.items():
493
+ if args.used_by is not None and assy.count == 0:
494
+ continue
495
+
496
+ line = "\t"
497
+ if args.recursive:
498
+ line += "%s" % project_name
499
+ line += " " + " " * (35 - len(project_name))
500
+ line += "%s" % assy_name
501
+ if args.used_by is not None:
502
+ assy = project.assemblies[assy_name]
503
+ line += "(%d)" % assy.count
504
+ assy_count = assy_count + assy.count
505
+ line += " " + " " * (35 - len(assy_name))
506
+
507
+ desc = assy.desc if assy.desc is not None else ""
508
+ desc = desc.replace(
509
+ "\n", "\n" + " " * (80 if args.recursive else 44)
510
+ )
511
+ line += "%s" % desc
512
+ output += line + "\n"
513
+ assy_kinds = assy_kinds + 1
514
+
515
+ if assy_kinds > 0:
516
+ if args.used_by is None:
517
+ output += "Total: %d\n" % assy_kinds
518
+ else:
519
+ output += "Total: %d assemblies of %d kinds\n" % (
520
+ assy_count,
521
+ assy_kinds,
522
+ )
523
+ else:
524
+ output += "\t<none>\n"
525
+ pc.logging.info(output)
@@ -10,6 +10,7 @@
10
10
  import os
11
11
  import threading
12
12
 
13
+ from partcad import __version__ as version
13
14
  import partcad.logging as pc_logging
14
15
  import partcad.user_config as user_config
15
16
 
@@ -37,6 +38,8 @@ def get_size(start_path="."):
37
38
 
38
39
  def cli_status(args):
39
40
  with pc_logging.Process("Status", "this"):
41
+ pc_logging.info("PartCAD version: %s" % version)
42
+
40
43
  path = user_config.internal_state_dir
41
44
  pc_logging.info("Internal data storage location: %s" % path)
42
45
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: partcad-cli
3
- Version: 0.5.22
3
+ Version: 0.6.2
4
4
  Summary: Command-line interface to PartCAD
5
5
  Author-email: Roman Kuzmenko <openvmp@proton.me>
6
6
  Maintainer-email: Roman Kuzmenko <openvmp@proton.me>
@@ -12,7 +12,7 @@ Classifier: License :: OSI Approved :: Apache Software License
12
12
  Classifier: Operating System :: OS Independent
13
13
  Requires-Python: >=3.10
14
14
  Description-Content-Type: text/markdown
15
- Requires-Dist: partcad==0.5.22
15
+ Requires-Dist: partcad==0.6.2
16
16
  Requires-Dist: renderlab
17
17
  Requires-Dist: rlPyCairo
18
18
  Requires-Dist: svglib
@@ -30,14 +30,22 @@ Requires-Dist: ocp_vscode
30
30
 
31
31
  PartCAD is the first package manager for CAD models
32
32
  and a framework for managing assemblies.
33
- It complements Git with everything necessary to substitute
33
+ It aims to complement Git with everything necessary to substitute
34
34
  commercial Product Lifecycle Management (PLM) tools.
35
35
 
36
36
  PartCAD maintains information about mechanical parts and
37
37
  how they come together to form larger assemblies.
38
- The same parts are reused in multiple assemblies and multiple projects.
38
+ The same parts can be reused in multiple assemblies and multiple projects.
39
39
  And all of that is supercharged by the ultimate versioning and collaboration features of Git.
40
40
 
41
+ PartCAD features include:
42
+
43
+ - 3D part models using STEP, STL and 3MF files
44
+ - 3D part models using CadQuery, build123d and OpenSCAD scripting languages (including AI-generated: Gemini and GPT)
45
+ - 2D blueprints using DXF, build123d and SVG files
46
+ - Fully featured object-oriented approach to maintain part interfaces and mating information (with multiple class inheritance etc)
47
+ - Live preview of 3D models while coding in VS Code
48
+
41
49
  Find [more documentation here](https://partcad.readthedocs.io/en/latest/?badge=latest) and visit [our website](https://partcad.org/).
42
50
 
43
51
  ## Installation
@@ -1,4 +1,4 @@
1
- partcad==0.5.22
1
+ partcad==0.6.2
2
2
  renderlab
3
3
  rlPyCairo
4
4
  svglib
@@ -1,245 +0,0 @@
1
- #
2
- # OpenVMP, 2023
3
- #
4
- # Author: Roman Kuzmenko
5
- # Created: 2023-12-23
6
- #
7
- # Licensed under Apache License, Version 2.0.
8
- #
9
-
10
- import time
11
-
12
- import partcad as pc
13
-
14
-
15
- def cli_help_list(subparsers):
16
- parser_list = subparsers.add_parser(
17
- "list",
18
- help="List imported packages",
19
- )
20
- parser_list_all = subparsers.add_parser(
21
- "list-all",
22
- help="List available parts, assemblies and scenes",
23
- )
24
- parser_list_parts = subparsers.add_parser(
25
- "list-parts",
26
- help="List available parts",
27
- )
28
- parser_list_assemblies = subparsers.add_parser(
29
- "list-assemblies",
30
- help="List available assemblies",
31
- )
32
-
33
- parser_list_all.add_argument(
34
- "-r",
35
- help="Recursively process all imported packages",
36
- dest="recursive",
37
- action="store_true",
38
- )
39
- parser_list_parts.add_argument(
40
- "-r",
41
- help="Recursively process all imported packages",
42
- dest="recursive",
43
- action="store_true",
44
- )
45
- parser_list_assemblies.add_argument(
46
- "-r",
47
- help="Recursively process all imported packages",
48
- dest="recursive",
49
- action="store_true",
50
- )
51
-
52
- parser_list_all.add_argument(
53
- "-u",
54
- help="Only process objects used by the given assembly or scene.",
55
- dest="used_by",
56
- type=str,
57
- required=False,
58
- )
59
- parser_list_parts.add_argument(
60
- "-u",
61
- help="Only process objects used by the given assembly or scene.",
62
- dest="used_by",
63
- type=str,
64
- required=False,
65
- )
66
- parser_list_assemblies.add_argument(
67
- "-u",
68
- help="Only process objects used by the given assembly or scene.",
69
- dest="used_by",
70
- type=str,
71
- required=False,
72
- )
73
-
74
- parser_list_parts.add_argument(
75
- "package",
76
- help="Package to retrieve the object from",
77
- type=str,
78
- nargs="?",
79
- )
80
- parser_list_assemblies.add_argument(
81
- "package",
82
- help="Package to retrieve the object from",
83
- type=str,
84
- nargs="?",
85
- )
86
-
87
-
88
- def cli_list(args, ctx):
89
- pkg_count = 0
90
-
91
- projects = ctx.get_all_packages()
92
- projects = sorted(projects, key=lambda p: p["name"])
93
-
94
- # TODO(clairbee): remove the following workaround after replacing 'print'
95
- # with corresponding logging calls
96
- time.sleep(2)
97
-
98
- output = "PartCAD packages:\n"
99
- for project in projects:
100
- project_name = project["name"]
101
-
102
- line = "\t%s" % project_name
103
- padding_size = 60 - len(project_name)
104
- if padding_size < 4:
105
- padding_size = 4
106
- line += " " * padding_size
107
- line += "%s" % project["desc"]
108
- output += line + "\n"
109
- pkg_count = pkg_count + 1
110
-
111
- if pkg_count < 1:
112
- output += "\t<none>\n"
113
- pc.logging.info(output)
114
-
115
-
116
- def cli_list_parts(args, ctx):
117
- part_count = 0
118
- part_kinds = 0
119
-
120
- if args.used_by is not None:
121
- pc.logging.info("Instantiating %s..." % args.used_by)
122
- ctx.get_assembly(args.used_by)
123
- else:
124
- ctx.get_all_packages()
125
-
126
- # TODO(clairbee): remove the following workaround after replacing 'print'
127
- # with corresponding logging calls
128
- time.sleep(2)
129
-
130
- output = "PartCAD parts:\n"
131
- for project_name in ctx.projects:
132
- if (
133
- hasattr(args, "package")
134
- and not args.package is None
135
- and args.package != project_name
136
- ):
137
- continue
138
-
139
- if project_name != ctx.get_current_project_path() and (
140
- not args.recursive
141
- and hasattr(args, "package")
142
- and args.package is None
143
- ):
144
- continue
145
- if project_name.startswith("partcad-"):
146
- continue
147
- project = ctx.projects[project_name]
148
-
149
- for part_name, part in project.parts.items():
150
- if args.used_by is not None and part.count == 0:
151
- continue
152
-
153
- line = "\t"
154
- if args.recursive:
155
- line += "%s" % project_name
156
- line += " " + " " * (35 - len(project_name))
157
- line += "%s" % part_name
158
- if args.used_by is not None:
159
- part = project.parts[part_name]
160
- line += "(%d)" % part.count
161
- part_count = part_count + part.count
162
- line += " " + " " * (35 - len(part_name))
163
-
164
- desc = part.desc
165
- desc = desc.replace("\n", "\n" + " " * 44)
166
- line += "%s" % desc
167
- output += line + "\n"
168
- part_kinds = part_kinds + 1
169
-
170
- if part_kinds > 0:
171
- if args.used_by is None:
172
- output += "Total: %d\n" % part_kinds
173
- else:
174
- output += "Total: %d parts of %d kinds\n" % (part_count, part_kinds)
175
- else:
176
- output += "\t<none>\n"
177
- pc.logging.info(output)
178
-
179
-
180
- def cli_list_assemblies(args, ctx):
181
- assy_count = 0
182
- assy_kinds = 0
183
-
184
- if args.used_by is not None:
185
- print("Instantiating %s..." % args.used_by)
186
- # TODO(clairbee): do not call it twice in 'list-all'
187
- ctx.get_assembly(args.used_by)
188
- else:
189
- ctx.get_all_packages()
190
-
191
- # TODO(clairbee): remove the following workaround after replacing 'print'
192
- # with corresponding logging calls
193
- time.sleep(2)
194
-
195
- output = "PartCAD assemblies:\n"
196
- for project_name in ctx.projects:
197
- if (
198
- hasattr(args, "package")
199
- and not args.package is None
200
- and args.package != project_name
201
- ):
202
- continue
203
-
204
- if project_name != ctx.get_current_project_path() and (
205
- not args.recursive
206
- and hasattr(args, "package")
207
- and args.package is None
208
- ):
209
- continue
210
- if project_name.startswith("partcad-"):
211
- continue
212
- project = ctx.projects[project_name]
213
-
214
- for assy_name, assy in project.assemblies.items():
215
- if args.used_by is not None and assy.count == 0:
216
- continue
217
-
218
- line = "\t"
219
- if args.recursive:
220
- line += "%s" % project_name
221
- line += " " + " " * (35 - len(project_name))
222
- line += "%s" % assy_name
223
- if args.used_by is not None:
224
- assy = project.assemblies[assy_name]
225
- line += "(%d)" % assy.count
226
- assy_count = assy_count + assy.count
227
- line += " " + " " * (35 - len(assy_name))
228
-
229
- desc = assy.desc
230
- desc = desc.replace("\n", "\n" + " " * 44)
231
- line += "%s" % desc
232
- output += line + "\n"
233
- assy_kinds = assy_kinds + 1
234
-
235
- if assy_kinds > 0:
236
- if args.used_by is None:
237
- output += "Total: %d\n" % assy_kinds
238
- else:
239
- output += "Total: %d assemblies of %d kinds\n" % (
240
- assy_count,
241
- assy_kinds,
242
- )
243
- else:
244
- output += "\t<none>\n"
245
- pc.logging.info(output)
File without changes