mirror of
https://github.com/GNS3/gns3-server.git
synced 2025-06-01 15:20:59 +00:00
parent
5ab85e5c9e
commit
40af2a35e0
@ -338,13 +338,24 @@ class Controller:
|
|||||||
|
|
||||||
def get_project(self, project_id):
|
def get_project(self, project_id):
|
||||||
"""
|
"""
|
||||||
Returns a compute server or raise a 404 error.
|
Returns a project or raise a 404 error.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return self._projects[project_id]
|
return self._projects[project_id]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise aiohttp.web.HTTPNotFound(text="Project ID {} doesn't exist".format(project_id))
|
raise aiohttp.web.HTTPNotFound(text="Project ID {} doesn't exist".format(project_id))
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def get_loaded_project(self, project_id):
|
||||||
|
"""
|
||||||
|
Returns a project or raise a 404 error.
|
||||||
|
|
||||||
|
If project is not finished to load wait for it
|
||||||
|
"""
|
||||||
|
project = self.get_project(project_id)
|
||||||
|
yield from project.wait_loaded()
|
||||||
|
return project
|
||||||
|
|
||||||
def remove_project(self, project):
|
def remove_project(self, project):
|
||||||
del self._projects[project.id]
|
del self._projects[project.id]
|
||||||
|
|
||||||
|
@ -78,6 +78,7 @@ class Project:
|
|||||||
self._status = status
|
self._status = status
|
||||||
self._scene_height = scene_height
|
self._scene_height = scene_height
|
||||||
self._scene_width = scene_width
|
self._scene_width = scene_width
|
||||||
|
self._loading = False
|
||||||
|
|
||||||
# Disallow overwrite of existing project
|
# Disallow overwrite of existing project
|
||||||
if project_id is None and path is not None:
|
if project_id is None and path is not None:
|
||||||
@ -618,10 +619,12 @@ class Project:
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.reset()
|
self.reset()
|
||||||
|
self._loading = True
|
||||||
self._status = "opened"
|
self._status = "opened"
|
||||||
|
|
||||||
path = self._topology_file()
|
path = self._topology_file()
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
|
self._loading = False
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
shutil.copy(path, path + ".backup")
|
shutil.copy(path, path + ".backup")
|
||||||
@ -655,16 +658,26 @@ class Project:
|
|||||||
if os.path.exists(path + ".backup"):
|
if os.path.exists(path + ".backup"):
|
||||||
shutil.copy(path + ".backup", path)
|
shutil.copy(path + ".backup", path)
|
||||||
self._status = "closed"
|
self._status = "closed"
|
||||||
|
self._loading = False
|
||||||
raise e
|
raise e
|
||||||
try:
|
try:
|
||||||
os.remove(path + ".backup")
|
os.remove(path + ".backup")
|
||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
self._loading = False
|
||||||
# Should we start the nodes when project is open
|
# Should we start the nodes when project is open
|
||||||
if self._auto_start:
|
if self._auto_start:
|
||||||
yield from self.start_all()
|
yield from self.start_all()
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def wait_loaded(self):
|
||||||
|
"""
|
||||||
|
Wait until the project finish loading
|
||||||
|
"""
|
||||||
|
while self._loading:
|
||||||
|
yield from asyncio.sleep(0.5)
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def duplicate(self, name=None, location=None):
|
def duplicate(self, name=None, location=None):
|
||||||
"""
|
"""
|
||||||
|
@ -41,8 +41,7 @@ class DrawingHandler:
|
|||||||
description="List drawings of a project")
|
description="List drawings of a project")
|
||||||
def list_drawings(request, response):
|
def list_drawings(request, response):
|
||||||
|
|
||||||
controller = Controller.instance()
|
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
project = controller.get_project(request.match_info["project_id"])
|
|
||||||
response.json([v for v in project.drawings.values()])
|
response.json([v for v in project.drawings.values()])
|
||||||
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
@ -59,8 +58,7 @@ class DrawingHandler:
|
|||||||
output=DRAWING_OBJECT_SCHEMA)
|
output=DRAWING_OBJECT_SCHEMA)
|
||||||
def create(request, response):
|
def create(request, response):
|
||||||
|
|
||||||
controller = Controller.instance()
|
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
project = controller.get_project(request.match_info["project_id"])
|
|
||||||
drawing = yield from project.add_drawing(**request.json)
|
drawing = yield from project.add_drawing(**request.json)
|
||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
response.json(drawing)
|
response.json(drawing)
|
||||||
@ -80,8 +78,7 @@ class DrawingHandler:
|
|||||||
output=DRAWING_OBJECT_SCHEMA)
|
output=DRAWING_OBJECT_SCHEMA)
|
||||||
def update(request, response):
|
def update(request, response):
|
||||||
|
|
||||||
controller = Controller.instance()
|
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
project = controller.get_project(request.match_info["project_id"])
|
|
||||||
drawing = project.get_drawing(request.match_info["drawing_id"])
|
drawing = project.get_drawing(request.match_info["drawing_id"])
|
||||||
yield from drawing.update(**request.json)
|
yield from drawing.update(**request.json)
|
||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
@ -100,7 +97,6 @@ class DrawingHandler:
|
|||||||
description="Delete a drawing instance")
|
description="Delete a drawing instance")
|
||||||
def delete(request, response):
|
def delete(request, response):
|
||||||
|
|
||||||
controller = Controller.instance()
|
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
project = controller.get_project(request.match_info["project_id"])
|
|
||||||
yield from project.delete_drawing(request.match_info["drawing_id"])
|
yield from project.delete_drawing(request.match_info["drawing_id"])
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
@ -43,8 +43,7 @@ class LinkHandler:
|
|||||||
description="List links of a project")
|
description="List links of a project")
|
||||||
def list_links(request, response):
|
def list_links(request, response):
|
||||||
|
|
||||||
controller = Controller.instance()
|
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
project = controller.get_project(request.match_info["project_id"])
|
|
||||||
response.json([v for v in project.links.values()])
|
response.json([v for v in project.links.values()])
|
||||||
|
|
||||||
@Route.post(
|
@Route.post(
|
||||||
@ -61,8 +60,7 @@ class LinkHandler:
|
|||||||
output=LINK_OBJECT_SCHEMA)
|
output=LINK_OBJECT_SCHEMA)
|
||||||
def create(request, response):
|
def create(request, response):
|
||||||
|
|
||||||
controller = Controller.instance()
|
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
project = controller.get_project(request.match_info["project_id"])
|
|
||||||
link = yield from project.add_link()
|
link = yield from project.add_link()
|
||||||
try:
|
try:
|
||||||
for node in request.json["nodes"]:
|
for node in request.json["nodes"]:
|
||||||
@ -91,8 +89,7 @@ class LinkHandler:
|
|||||||
output=LINK_OBJECT_SCHEMA)
|
output=LINK_OBJECT_SCHEMA)
|
||||||
def update(request, response):
|
def update(request, response):
|
||||||
|
|
||||||
controller = Controller.instance()
|
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
project = controller.get_project(request.match_info["project_id"])
|
|
||||||
link = project.get_link(request.match_info["link_id"])
|
link = project.get_link(request.match_info["link_id"])
|
||||||
yield from link.update_nodes(request.json["nodes"])
|
yield from link.update_nodes(request.json["nodes"])
|
||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
@ -113,8 +110,7 @@ class LinkHandler:
|
|||||||
description="Start capture on a link instance. By default we consider it as an Ethernet link")
|
description="Start capture on a link instance. By default we consider it as an Ethernet link")
|
||||||
def start_capture(request, response):
|
def start_capture(request, response):
|
||||||
|
|
||||||
controller = Controller.instance()
|
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
project = controller.get_project(request.match_info["project_id"])
|
|
||||||
link = project.get_link(request.match_info["link_id"])
|
link = project.get_link(request.match_info["link_id"])
|
||||||
yield from link.start_capture(data_link_type=request.json.get("data_link_type", "DLT_EN10MB"), capture_file_name=request.json.get("capture_file_name"))
|
yield from link.start_capture(data_link_type=request.json.get("data_link_type", "DLT_EN10MB"), capture_file_name=request.json.get("capture_file_name"))
|
||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
@ -133,8 +129,7 @@ class LinkHandler:
|
|||||||
description="Stop capture on a link instance")
|
description="Stop capture on a link instance")
|
||||||
def stop_capture(request, response):
|
def stop_capture(request, response):
|
||||||
|
|
||||||
controller = Controller.instance()
|
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
project = controller.get_project(request.match_info["project_id"])
|
|
||||||
link = project.get_link(request.match_info["link_id"])
|
link = project.get_link(request.match_info["link_id"])
|
||||||
yield from link.stop_capture()
|
yield from link.stop_capture()
|
||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
@ -153,8 +148,7 @@ class LinkHandler:
|
|||||||
description="Delete a link instance")
|
description="Delete a link instance")
|
||||||
def delete(request, response):
|
def delete(request, response):
|
||||||
|
|
||||||
controller = Controller.instance()
|
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
project = controller.get_project(request.match_info["project_id"])
|
|
||||||
yield from project.delete_link(request.match_info["link_id"])
|
yield from project.delete_link(request.match_info["link_id"])
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@ -172,8 +166,7 @@ class LinkHandler:
|
|||||||
})
|
})
|
||||||
def pcap(request, response):
|
def pcap(request, response):
|
||||||
|
|
||||||
controller = Controller.instance()
|
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
project = controller.get_project(request.match_info["project_id"])
|
|
||||||
link = project.get_link(request.match_info["link_id"])
|
link = project.get_link(request.match_info["link_id"])
|
||||||
|
|
||||||
if link.capture_file_path is None:
|
if link.capture_file_path is None:
|
||||||
|
@ -49,7 +49,7 @@ class NodeHandler:
|
|||||||
|
|
||||||
controller = Controller.instance()
|
controller = Controller.instance()
|
||||||
compute = controller.get_compute(request.json.pop("compute_id"))
|
compute = controller.get_compute(request.json.pop("compute_id"))
|
||||||
project = controller.get_project(request.match_info["project_id"])
|
project = yield from controller.get_loaded_project(request.match_info["project_id"])
|
||||||
node = yield from project.add_node(compute, request.json.pop("name"), request.json.pop("node_id", None), **request.json)
|
node = yield from project.add_node(compute, request.json.pop("name"), request.json.pop("node_id", None), **request.json)
|
||||||
response.set_status(201)
|
response.set_status(201)
|
||||||
response.json(node)
|
response.json(node)
|
||||||
@ -80,8 +80,7 @@ class NodeHandler:
|
|||||||
description="List nodes of a project")
|
description="List nodes of a project")
|
||||||
def list_nodes(request, response):
|
def list_nodes(request, response):
|
||||||
|
|
||||||
controller = Controller.instance()
|
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
project = controller.get_project(request.match_info["project_id"])
|
|
||||||
response.json([v for v in project.nodes.values()])
|
response.json([v for v in project.nodes.values()])
|
||||||
|
|
||||||
@Route.put(
|
@Route.put(
|
||||||
@ -95,7 +94,7 @@ class NodeHandler:
|
|||||||
input=NODE_UPDATE_SCHEMA,
|
input=NODE_UPDATE_SCHEMA,
|
||||||
output=NODE_OBJECT_SCHEMA)
|
output=NODE_OBJECT_SCHEMA)
|
||||||
def update(request, response):
|
def update(request, response):
|
||||||
project = Controller.instance().get_project(request.match_info["project_id"])
|
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
node = project.get_node(request.match_info["node_id"])
|
node = project.get_node(request.match_info["node_id"])
|
||||||
|
|
||||||
# Ignore these because we only use them when creating a node
|
# Ignore these because we only use them when creating a node
|
||||||
@ -121,7 +120,7 @@ class NodeHandler:
|
|||||||
output=NODE_OBJECT_SCHEMA)
|
output=NODE_OBJECT_SCHEMA)
|
||||||
def start_all(request, response):
|
def start_all(request, response):
|
||||||
|
|
||||||
project = Controller.instance().get_project(request.match_info["project_id"])
|
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
yield from project.start_all()
|
yield from project.start_all()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@ -139,7 +138,7 @@ class NodeHandler:
|
|||||||
output=NODE_OBJECT_SCHEMA)
|
output=NODE_OBJECT_SCHEMA)
|
||||||
def stop_all(request, response):
|
def stop_all(request, response):
|
||||||
|
|
||||||
project = Controller.instance().get_project(request.match_info["project_id"])
|
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
yield from project.stop_all()
|
yield from project.stop_all()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@ -157,7 +156,7 @@ class NodeHandler:
|
|||||||
output=NODE_OBJECT_SCHEMA)
|
output=NODE_OBJECT_SCHEMA)
|
||||||
def suspend_all(request, response):
|
def suspend_all(request, response):
|
||||||
|
|
||||||
project = Controller.instance().get_project(request.match_info["project_id"])
|
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
yield from project.suspend_all()
|
yield from project.suspend_all()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@ -175,7 +174,7 @@ class NodeHandler:
|
|||||||
output=NODE_OBJECT_SCHEMA)
|
output=NODE_OBJECT_SCHEMA)
|
||||||
def reload_all(request, response):
|
def reload_all(request, response):
|
||||||
|
|
||||||
project = Controller.instance().get_project(request.match_info["project_id"])
|
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
yield from project.stop_all()
|
yield from project.stop_all()
|
||||||
yield from project.start_all()
|
yield from project.start_all()
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
@ -195,7 +194,7 @@ class NodeHandler:
|
|||||||
output=NODE_OBJECT_SCHEMA)
|
output=NODE_OBJECT_SCHEMA)
|
||||||
def start(request, response):
|
def start(request, response):
|
||||||
|
|
||||||
project = Controller.instance().get_project(request.match_info["project_id"])
|
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
node = project.get_node(request.match_info["node_id"])
|
node = project.get_node(request.match_info["node_id"])
|
||||||
yield from node.start()
|
yield from node.start()
|
||||||
response.json(node)
|
response.json(node)
|
||||||
@ -216,7 +215,7 @@ class NodeHandler:
|
|||||||
output=NODE_OBJECT_SCHEMA)
|
output=NODE_OBJECT_SCHEMA)
|
||||||
def stop(request, response):
|
def stop(request, response):
|
||||||
|
|
||||||
project = Controller.instance().get_project(request.match_info["project_id"])
|
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
node = project.get_node(request.match_info["node_id"])
|
node = project.get_node(request.match_info["node_id"])
|
||||||
yield from node.stop()
|
yield from node.stop()
|
||||||
response.json(node)
|
response.json(node)
|
||||||
@ -237,7 +236,7 @@ class NodeHandler:
|
|||||||
output=NODE_OBJECT_SCHEMA)
|
output=NODE_OBJECT_SCHEMA)
|
||||||
def suspend(request, response):
|
def suspend(request, response):
|
||||||
|
|
||||||
project = Controller.instance().get_project(request.match_info["project_id"])
|
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
node = project.get_node(request.match_info["node_id"])
|
node = project.get_node(request.match_info["node_id"])
|
||||||
yield from node.suspend()
|
yield from node.suspend()
|
||||||
response.json(node)
|
response.json(node)
|
||||||
@ -258,7 +257,7 @@ class NodeHandler:
|
|||||||
output=NODE_OBJECT_SCHEMA)
|
output=NODE_OBJECT_SCHEMA)
|
||||||
def reload(request, response):
|
def reload(request, response):
|
||||||
|
|
||||||
project = Controller.instance().get_project(request.match_info["project_id"])
|
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
node = project.get_node(request.match_info["node_id"])
|
node = project.get_node(request.match_info["node_id"])
|
||||||
yield from node.reload()
|
yield from node.reload()
|
||||||
response.json(node)
|
response.json(node)
|
||||||
@ -277,7 +276,7 @@ class NodeHandler:
|
|||||||
},
|
},
|
||||||
description="Delete a node instance")
|
description="Delete a node instance")
|
||||||
def delete(request, response):
|
def delete(request, response):
|
||||||
project = Controller.instance().get_project(request.match_info["project_id"])
|
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
yield from project.delete_node(request.match_info["node_id"])
|
yield from project.delete_node(request.match_info["node_id"])
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
@ -295,7 +294,7 @@ class NodeHandler:
|
|||||||
description="Compute the IDLE PC for a Dynamips node")
|
description="Compute the IDLE PC for a Dynamips node")
|
||||||
def auto_idlepc(request, response):
|
def auto_idlepc(request, response):
|
||||||
|
|
||||||
project = Controller.instance().get_project(request.match_info["project_id"])
|
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
node = project.get_node(request.match_info["node_id"])
|
node = project.get_node(request.match_info["node_id"])
|
||||||
idle = yield from node.dynamips_auto_idlepc()
|
idle = yield from node.dynamips_auto_idlepc()
|
||||||
response.json(idle)
|
response.json(idle)
|
||||||
@ -315,7 +314,7 @@ class NodeHandler:
|
|||||||
description="Compute a list of potential idle PC for a node")
|
description="Compute a list of potential idle PC for a node")
|
||||||
def idlepc_proposals(request, response):
|
def idlepc_proposals(request, response):
|
||||||
|
|
||||||
project = Controller.instance().get_project(request.match_info["project_id"])
|
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
node = project.get_node(request.match_info["node_id"])
|
node = project.get_node(request.match_info["node_id"])
|
||||||
idle = yield from node.dynamips_idlepc_proposals()
|
idle = yield from node.dynamips_idlepc_proposals()
|
||||||
response.json(idle)
|
response.json(idle)
|
||||||
@ -335,7 +334,7 @@ class NodeHandler:
|
|||||||
description="Get a file in the node directory")
|
description="Get a file in the node directory")
|
||||||
def get_file(request, response):
|
def get_file(request, response):
|
||||||
|
|
||||||
project = Controller.instance().get_project(request.match_info["project_id"])
|
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
node = project.get_node(request.match_info["node_id"])
|
node = project.get_node(request.match_info["node_id"])
|
||||||
path = request.match_info["path"]
|
path = request.match_info["path"]
|
||||||
path = os.path.normpath(path)
|
path = os.path.normpath(path)
|
||||||
@ -375,7 +374,7 @@ class NodeHandler:
|
|||||||
description="Write a file in the node directory")
|
description="Write a file in the node directory")
|
||||||
def post_file(request, response):
|
def post_file(request, response):
|
||||||
|
|
||||||
project = Controller.instance().get_project(request.match_info["project_id"])
|
project = yield from Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
node = project.get_node(request.match_info["node_id"])
|
node = project.get_node(request.match_info["node_id"])
|
||||||
path = request.match_info["path"]
|
path = request.match_info["path"]
|
||||||
path = os.path.normpath(path)
|
path = os.path.normpath(path)
|
||||||
|
@ -284,7 +284,7 @@ class ProjectHandler:
|
|||||||
def export_project(request, response):
|
def export_project(request, response):
|
||||||
|
|
||||||
controller = Controller.instance()
|
controller = Controller.instance()
|
||||||
project = controller.get_project(request.match_info["project_id"])
|
project = yield from controller.get_loaded_project(request.match_info["project_id"])
|
||||||
|
|
||||||
with tempfile.TemporaryDirectory() as tmp_dir:
|
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||||
datas = yield from export_project(project, tmp_dir, include_images=bool(request.get("include_images", "0")))
|
datas = yield from export_project(project, tmp_dir, include_images=bool(request.get("include_images", "0")))
|
||||||
@ -360,7 +360,7 @@ class ProjectHandler:
|
|||||||
def duplicate(request, response):
|
def duplicate(request, response):
|
||||||
|
|
||||||
controller = Controller.instance()
|
controller = Controller.instance()
|
||||||
project = controller.get_project(request.match_info["project_id"])
|
project = yield from controller.get_loaded_project(request.match_info["project_id"])
|
||||||
|
|
||||||
if request.json.get("path"):
|
if request.json.get("path"):
|
||||||
config = Config.instance()
|
config = Config.instance()
|
||||||
@ -390,7 +390,7 @@ class ProjectHandler:
|
|||||||
def get_file(request, response):
|
def get_file(request, response):
|
||||||
|
|
||||||
controller = Controller.instance()
|
controller = Controller.instance()
|
||||||
project = controller.get_project(request.match_info["project_id"])
|
project = yield from controller.get_loaded_project(request.match_info["project_id"])
|
||||||
path = request.match_info["path"]
|
path = request.match_info["path"]
|
||||||
path = os.path.normpath(path)
|
path = os.path.normpath(path)
|
||||||
|
|
||||||
@ -434,7 +434,7 @@ class ProjectHandler:
|
|||||||
def write_file(request, response):
|
def write_file(request, response):
|
||||||
|
|
||||||
controller = Controller.instance()
|
controller = Controller.instance()
|
||||||
project = controller.get_project(request.match_info["project_id"])
|
project = yield from controller.get_loaded_project(request.match_info["project_id"])
|
||||||
path = request.match_info["path"]
|
path = request.match_info["path"]
|
||||||
path = os.path.normpath(path)
|
path = os.path.normpath(path)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user