Command Line Interface and MS Project Resource Parsing (#1845)

* implemented initial cli and support for resource parsing for ms project

* Added command line interface and resource support for MS Project XML files

* Removed the test code

* Check for output exists before writting the file to avoid failure
This commit is contained in:
HassanEmam
2021-10-30 12:29:10 +01:00
committed by GitHub
parent 02461233a6
commit 2d8ec8a6bf
5 changed files with 192 additions and 59 deletions
+70
View File
@@ -0,0 +1,70 @@
import os
import sys
import argparse
from p6xer2ifc import P6XER2Ifc
from p62ifc import P62Ifc
from msp2ifc import MSP2Ifc
import ifcopenshell
parser = argparse.ArgumentParser()
parser .add_argument('-f','--file', action='store', type=str,
required=True, help="schedule file name to be parsed")
parser .add_argument('-s','--schedule', action='store', required=True,
type=str, help='file format as xer, p6xml, mspxml')
parser .add_argument('-i', '--ifcfile', action='store', required=False,
type=str, help='ifc file name as string e.g. \"file.ifc\"')
parser .add_argument('-o', '--output', action='store', required=True,
type=str, help='ifc file name as string e.g. \"file.ifc\"')
args = parser .parse_args()
def get_file():
ifcfile = None
if args.ifcfile:
ifcfile = ifcopenshell.open(args.ifcfile)
elif args.output:
ifc = ifcopenshell.file(schema='IFC4')
ifc.create_entity("IfcWorkPlan")
ifc.create_entity("IfcContext")
ifc.write(args.output)
ifcfile = ifcopenshell.open(args.output)
else:
ifcfile = None
return ifcfile
if not args.ifcfile:
print("You need to provide an ifc file to add schedule")
print("Examples python ifc4d -i model.ifc -s xer -f schedule.xer -o newifc.ifc")
elif not args.output:
print("an output file is required to save changes")
print("python ifc4d -o newfile.ifc -s xer -f schedule.xer")
elif args.schedule== "xer":
p6xer = P6XER2Ifc()
p6xer.xer = args.file
p6xer.output = args.output
ifcfile = get_file()
if ifcfile:
p6xer.file = ifcfile
p6xer.execute()
else: raise Exception("No files provided for output")
elif args.schedule == "mspxml":
msp = MSP2Ifc()
msp.xml = args.file()
msp.output = args.output
ifcfile = get_file()
if ifcfile:
msp.file = ifcfile
msp.execute()
elif args.schedule == "p6xml":
p6xml = P62Ifc()
p6xml.output = args.output
p6xml.xml = args.file
ifcfile = get_file()
if ifcfile:
p6xml.file = ifcopenshell.open(args.ifcfile)
p6xml.execute()
else:
print("schedule type you selected is not implemented at the moment")
+51 -46
View File
@@ -7,17 +7,17 @@ from datetime import datetime, timedelta, date
class ScheduleIfcGenerator: class ScheduleIfcGenerator:
def __init__(self, file, work_plan, project, calendars, wbs, def __init__(self, file, output, settings):
root_activites, activities, relationships, resources):
self.file = file self.file = file
self.work_plan = work_plan self.work_plan = settings['work_plan']
self.project = project self.project = settings['project']
self.calendars = calendars self.calendars = settings['calendars']
self.wbs = wbs self.wbs = settings['wbs']
self.root_activites = root_activites self.root_activites = settings['root_activities']
self.activities = activities self.activities = settings['activities']
self.relationships = relationships self.relationships = settings['relationships']
self.resources = resources self.resources = settings['resources']
self.output = output
self.day_map = { self.day_map = {
"Monday": 1, "Monday": 1,
"Tuesday": 2, "Tuesday": 2,
@@ -38,6 +38,8 @@ class ScheduleIfcGenerator:
self.create_tasks(work_schedule) self.create_tasks(work_schedule)
self.create_rel_sequences() self.create_rel_sequences()
self.create_resources() self.create_resources()
if self.output:
self.file.write(self.output)
def create_work_schedule(self): def create_work_schedule(self):
return ifcopenshell.api.run( return ifcopenshell.api.run(
@@ -50,11 +52,11 @@ class ScheduleIfcGenerator:
"sequence.add_work_calendar", self.file, name=calendar["Name"] "sequence.add_work_calendar", self.file, name=calendar["Name"]
) )
self.process_working_week(calendar["StandardWorkWeek"], calendar["ifc"]) self.process_working_week(calendar["StandardWorkWeek"], calendar["ifc"])
self.process_exceptions(calendar["HolidayOrExceptions"], calendar["ifc"]) self.process_exceptions(calendar.get("HolidayOrExceptions"), calendar["ifc"])
def process_working_week(self, week, calendar): def process_working_week(self, week, calendar):
for day in week: for day in week:
if day["ifc"] or not day["WorkTimes"]: if day["ifc"] or not day.get("WorkTimes"):
continue continue
day["ifc"] = ifcopenshell.api.run( day["ifc"] = ifcopenshell.api.run(
@@ -96,12 +98,13 @@ class ScheduleIfcGenerator:
) )
def process_exceptions(self, exceptions, calendar): def process_exceptions(self, exceptions, calendar):
for year, year_data in exceptions.items(): if exceptions:
for month, month_data in year_data.items(): for year, year_data in exceptions.items():
if month_data["FullDay"]: for month, month_data in year_data.items():
self.process_full_day_exceptions(year, month, month_data, calendar) if month_data["FullDay"]:
if month_data["WorkTime"]: self.process_full_day_exceptions(year, month, month_data, calendar)
self.process_work_time_exceptions(year, month, month_data, calendar) if month_data["WorkTime"]:
self.process_work_time_exceptions(year, month, month_data, calendar)
def process_full_day_exceptions(self, year, month, month_data, calendar): def process_full_day_exceptions(self, year, month, month_data, calendar):
work_time = ifcopenshell.api.run( work_time = ifcopenshell.api.run(
@@ -288,35 +291,37 @@ class ScheduleIfcGenerator:
def create_resources(self): def create_resources(self):
# print("Resources", self.resources)
if self.resources:
for id, resource in self.resources.items():
for id, resource in self.resources.items(): parent = self.resources.get(resource.get("ParentObjectId"))
if parent:
parent = self.resources.get(resource.get("ParentObjectId")) if not parent.get("ifc"):
if parent: parent["ifc"] = ifcopenshell.api.run(
if not parent.get("ifc"): "resource.add_resource",
parent["ifc"] = ifcopenshell.api.run( self.file,
"resource.add_resource", **{"ifc_class": "IfcCrewResource",
self.file, "name": parent['Name']}
**{"ifc_class": "IfcCrewResource", )
"name": parent['Name']} if parent:
) resource["ifc"] = ifcopenshell.api.run(
if parent: "resource.add_resource",
resource["ifc"] = ifcopenshell.api.run( self.file,
"resource.add_resource", **{"parent_resource": parent["ifc"] if parent else None,
self.file, "ifc_class": "IfcCrewResource",
**{"parent_resource": parent["ifc"] if parent else None, "name": resource['Name']
"ifc_class": "IfcCrewResource", }
"name": resource['Name'] )
} else:
) resource["ifc"] = ifcopenshell.api.run(
else: "resource.add_resource",
resource["ifc"] = ifcopenshell.api.run( self.file,
"resource.add_resource", **{ "ifc_class": "IfcCrewResource",
self.file, "name": resource['Name']
**{ "ifc_class": "IfcCrewResource", }
"name": resource['Name'] )
} print(self.resources)
)
+44 -3
View File
@@ -36,15 +36,32 @@ class MSP2Ifc:
self.calendars = {} self.calendars = {}
self.wbs = {} self.wbs = {}
self.root_activites = [] self.root_activites = []
self.activities = []
self.tasks = {} self.tasks = {}
self.relationships = {} self.relationships = {}
self.resources = {}
self.output = None
self.RESOURCE_TYPES_MAPPING = {
'1' : "LABOR",
'0' : "MATERIAL",
'2' : None
}
def execute(self): def execute(self):
self.parse_xml() self.parse_xml()
ifcCreator = ScheduleIfcGenerator(self.file, self.work_plan, self.project, self.calendars, settings = {
self.wbs, self.root_activites, self.activities, self.relationships, None) "work_plan":self.work_plan,
"project": self.project,
"calendars": self.calendars,
"wbs": self.wbs,
"root_activities": self.root_activites,
"activities": self.activities,
"relationships": self.relationships,
"resources": self.resources
}
ifcCreator = ScheduleIfcGenerator(self.file, self.output, settings)
ifcCreator.create_ifc() ifcCreator.create_ifc()
#self.create_ifc()
def parse_xml(self): def parse_xml(self):
tree = ET.parse(self.xml) tree = ET.parse(self.xml)
@@ -55,6 +72,8 @@ class MSP2Ifc:
self.outline_parents = {} self.outline_parents = {}
self.parse_task_xml(project) self.parse_task_xml(project)
self.parse_calendar_xml(project) self.parse_calendar_xml(project)
self.parse_resources_xml(project)
def parse_relationship_xml(self, task): def parse_relationship_xml(self, task):
relationships = {} relationships = {}
@@ -124,3 +143,25 @@ class MSP2Ifc:
"Name": calendar.find("pr:Name", self.ns).text, "Name": calendar.find("pr:Name", self.ns).text,
"StandardWorkWeek": week_days, "StandardWorkWeek": week_days,
} }
def parse_resources_xml(self, project):
resources_lst = project.find("pr:Resources", self.ns)
resources = resources_lst.findall("pr:Resource", self.ns)
# print("Resource text", resources[4].find("pr:Name", self.ns).text)
for resource in resources:
name = resource.find("pr:Name", self.ns)
id = resource.find("pr:ID", self.ns).text
if name is not None:
name = name.text
else:
# print("- No Name")
name = None
self.resources[id] = {
"Name": name,
"Code": resource.find("pr:UID", self.ns).text,
"ParentObjectId": None,
"Type": self.RESOURCE_TYPES_MAPPING[resource.find("pr:Type", self.ns).text],
"ifc": None,
"rel": None,
}
print("Resource found", self.resources)
+13 -3
View File
@@ -23,7 +23,7 @@ import ifcopenshell
import ifcopenshell.api import ifcopenshell.api
import ifcopenshell.util.date import ifcopenshell.util.date
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from common import ScheduleIfcGenerator from .common import ScheduleIfcGenerator
class P62Ifc: class P62Ifc:
def __init__(self): def __init__(self):
@@ -37,6 +37,7 @@ class P62Ifc:
self.activities = {} self.activities = {}
self.relationships = {} self.relationships = {}
self.resources = {} self.resources = {}
self.output = None
self.day_map = { self.day_map = {
"Monday": 1, "Monday": 1,
"Tuesday": 2, "Tuesday": 2,
@@ -64,8 +65,17 @@ class P62Ifc:
start = time.time() start = time.time()
print("Started") print("Started")
self.parse_xml() self.parse_xml()
ifcCreator = ScheduleIfcGenerator(self.file, self.work_plan, self.project, self.calendars, settings = {
self.wbs, self.root_activites, self.activities, self.relationships, self.resources) "work_plan":self.work_plan,
"project": self.project,
"calendars": self.calendars,
"wbs": self.wbs,
"root_activities": self.root_activites,
"activities": self.activities,
"relationships": self.relationships,
"resources": self.resources
}
ifcCreator = ScheduleIfcGenerator(self.file, self.output, settings)
end = time.time() end = time.time()
ifcCreator.create_ifc() ifcCreator.create_ifc()
+12 -5
View File
@@ -65,7 +65,7 @@ class P6XER2Ifc():
self.activities = {} self.activities = {}
self.relationships = {} self.relationships = {}
self.resources = {} self.resources = {}
self.output = None
self.day_map2 = { self.day_map2 = {
'1': "Monday", '1': "Monday",
@@ -80,10 +80,18 @@ class P6XER2Ifc():
def execute(self): def execute(self):
self.parse_xer() self.parse_xer()
ifcCreator = ScheduleIfcGenerator(self.file, self.work_plan, self.project, self.calendars, settings = {
self.wbs, self.root_activites, self.activities, self.relationships, self.resources) "work_plan":self.work_plan,
"project": self.project,
"calendars": self.calendars,
"wbs": self.wbs,
"root_activities": self.root_activites,
"activities": self.activities,
"relationships": self.relationships,
"resources": self.resources
}
ifcCreator = ScheduleIfcGenerator(self.file, self.output, settings)
ifcCreator.create_ifc() ifcCreator.create_ifc()
# self.create_ifc()
def parse_xer(self): def parse_xer(self):
@@ -177,7 +185,6 @@ class P6XER2Ifc():
"ifc": None, "ifc": None,
"rel": None, "rel": None,
} }
print(dir(self.model.resources._rsrcs[0]), self.model.resources._rsrcs[0].rsrc_title_name)