gns3-server/pyproject.toml
2026-09-27 15:43:18 +03:00

432 lines
20 KiB
TOML

[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "gns3-server"
description = "GNS3 graphical interface for the GNS3 server."
license-files = ["LICENSE"]
authors = [
{ name = "Jeremy Grossmann", email = "developers@gns3.com" }
]
readme = "README.md"
requires-python = ">=3.10"
classifiers = [
"Development Status :: 5 - Production/Stable",
"Environment :: Console",
"Framework :: FastAPI",
"Intended Audience :: Information Technology",
"Topic :: System :: Networking",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Natural Language :: English",
"Operating System :: POSIX :: Linux",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: Implementation :: CPython"
]
dynamic = ["version", "dependencies", "optional-dependencies"]
[tool.setuptools.dynamic]
version = {attr = "gns3server.version.__version__"}
dependencies = {file = "requirements.txt"}
[tool.setuptools.dynamic.optional-dependencies]
# Development dependencies
dev = {file = ['dev-requirements.txt']}
# AI features bundle — installs both AI Copilot and MCP dependencies
ai-features = {file = ['ai-requirements.txt', 'mcp-requirements.txt']}
# terraform = {file = ['terraform-requirements.txt']} # Future component
[project.urls]
"Homepage" = "http://gns3.com"
"Repository" = "http://github.com/GNS3/gns3-server"
"Bug tracker" = "http://github.com/GNS3/gns3-server/issues"
[project.scripts]
gns3server = "gns3server.main:main"
gns3vmnet = "gns3server.utils.vmnet:main"
gns3server-web-wireshark-setup = "gns3server.agent.web_wireshark.setup_wireshark_image:main"
gns3server-uninstall-ai-features = "gns3server.utils.uninstall_ai_features:main"
[tool.setuptools]
packages = ["gns3server"]
[tool.ruff]
target-version = "py310"
line-length = 120
[tool.ruff.lint]
select = [
"ASYNC", # flake8-async
"B", # flake8-bugbear
"BLE", # flake8-blind-except
"C90", # mccabe
"DTZ", # flake8-datetimez
"E", # pycodestyle errors
"F", # pyflakes
"I", # isort
"LOG", # flake8-logging
"PLE", # pylint errors
"PLW", # pylint warnings
"RUF", # ruff-specific rules
"S", # flake8-bandit
"T10", # flake8-debugger
"UP", # pyupgrade
"W", # pycodestyle warnings
]
# Baseline: widespread rules that the existing code still violates
# (violation count at baseline time). Remove an entry, and fix its
# violations, in a dedicated small PR. Never add new entries here:
# fix the code or use a targeted "# noqa: CODE" with a reason.
ignore = [
"ASYNC230", # 240 blocking-open-call-in-async-function
"ASYNC240", # 235 blocking-path-method-in-async-function
"B007", # 32 unused-loop-control-variable
"B008", # 119 function-call-in-default-argument
"B904", # 365 raise-without-from-inside-except
"BLE001", # 214 blind-except
"E402", # 129 module-import-not-at-top-of-file
"E501", # 655 line-too-long
"F401", # 300 unused-import
"F541", # 16 f-string-missing-placeholders
"F841", # 32 unused-variable
"I001", # 441 unsorted-imports
"PLW0603", # 21 global-statement
"PLW2901", # 30 redefined-loop-name
"RUF010", # 65 explicit-f-string-type-conversion
"RUF012", # 23 mutable-class-default
"RUF013", # 40 implicit-optional
"RUF036", # 22 none-not-at-end-of-union
"RUF059", # 29 unused-unpacked-variable
"S101", # 19 assert
"S104", # 22 hardcoded-bind-all-interfaces
"S110", # 23 try-except-pass
"UP006", # 270 non-pep585-annotation
"UP007", # 81 non-pep604-annotation-union
"UP009", # 51 utf8-encoding-declaration
"UP032", # 560 f-string
"UP035", # 106 deprecated-import
"UP045", # 1100 non-pep604-annotation-optional
"W293", # 661 blank-line-with-whitespace
]
[tool.ruff.lint.mccabe]
max-complexity = 15
[tool.ruff.lint.flake8-bugbear]
# FastAPI dependency markers are meant to be used as defaults:
extend-immutable-calls = [
"fastapi.Body",
"fastapi.Cookie",
"fastapi.Depends",
"fastapi.File",
"fastapi.Form",
"fastapi.Header",
"fastapi.Path",
"fastapi.Query",
"fastapi.Security",
]
[tool.ruff.lint.per-file-ignores]
# Tests use asserts and hardcoded credentials / temp paths:
"tests/**" = ["S101", "S105", "S106", "S108"]
# Baseline: existing violations of rules that are enforced everywhere else.
# Remove entries one small PR at a time. Never add new ones.
"gns3server/agent/__init__.py" = ["LOG015", "RUF022"]
"gns3server/agent/gns3_copilot/agent/context_manager.py" = ["RUF005", "RUF100"]
"gns3server/agent/gns3_copilot/agent/gns3_copilot.py" = ["DTZ003"]
"gns3server/agent/gns3_copilot/agent_service.py" = ["C901", "DTZ003"]
"gns3server/agent/gns3_copilot/chat_sessions_repository.py" = ["DTZ003", "S608"]
"gns3server/agent/gns3_copilot/gns3_client/__init__.py" = ["RUF022"]
"gns3server/agent/gns3_copilot/gns3_client/context_helpers.py" = ["RUF022"]
"gns3server/agent/gns3_copilot/skills/__init__.py" = ["RUF022"]
"gns3server/agent/gns3_copilot/skills/loader.py" = ["UP015"]
"gns3server/agent/gns3_copilot/skills/manager.py" = ["UP037"]
"gns3server/agent/gns3_copilot/skills/registry.py" = ["C901"]
"gns3server/agent/gns3_copilot/tools_v2/__init__.py" = ["RUF022"]
"gns3server/agent/gns3_copilot/tools_v2/config_tools_nornir.py" = ["RUF100"]
"gns3server/agent/gns3_copilot/tools_v2/display_tools_nornir.py" = ["RUF100"]
"gns3server/agent/gns3_copilot/tools_v2/gns3_packet_filter.py" = ["PLW1510", "S603", "S607"]
"gns3server/agent/gns3_copilot/tools_v2/packet_analysis_tool.py" = ["PLW1510", "RUF005", "S603", "S607"]
"gns3server/agent/gns3_copilot/tools_v2/vpcs_tools_netmiko.py" = ["RUF100"]
"gns3server/agent/gns3_copilot/utils/__init__.py" = ["RUF022"]
"gns3server/agent/gns3_copilot/utils/custom_netmiko/__init__.py" = ["RUF100"]
"gns3server/agent/gns3_copilot/utils/custom_netmiko/huawei_ce.py" = ["S107"]
"gns3server/agent/gns3_copilot/utils/custom_netmiko/ruijie_telnet.py" = ["LOG015"]
"gns3server/agent/gns3_copilot/utils/custom_netmiko/scripts/list_netmiko_telnet_devices.py" = ["DTZ005", "UP024"]
"gns3server/agent/gns3_copilot/utils/custom_netmiko/tests/test_huawei_ce.py" = ["RUF100"]
"gns3server/agent/gns3_copilot/utils/custom_netmiko/tests/test_ruijie_telnet.py" = ["RUF100"]
"gns3server/agent/gns3_copilot/utils/custom_netmiko/tests/test_vpcs_telnet.py" = ["RUF100"]
"gns3server/agent/gns3_copilot/utils/custom_netmiko/vpcs_telnet.py" = ["S107"]
"gns3server/agent/gns3_copilot/utils/gns3_drawing_utils.py" = ["RUF100"]
"gns3server/agent/gns3_copilot/utils/message_converters.py" = ["RUF019"]
"gns3server/agent/gns3_copilot/utils/parse_tool_content.py" = ["C901", "DTZ003"]
"gns3server/agent/mcp/__init__.py" = ["RUF003"]
"gns3server/agent/mcp/device_config.py" = ["E741"]
"gns3server/agent/web_wireshark/manager.py" = ["C901"]
"gns3server/agent/web_wireshark/setup_wireshark_image.py" = ["PLW1510", "S603", "S607"]
"gns3server/agent/web_wireshark/stats.py" = ["ASYNC221", "PLW1510", "S603", "S607"]
"gns3server/api/routes/compute/notifications.py" = ["W291"]
"gns3server/api/routes/compute/qemu_nodes.py" = ["F811"]
"gns3server/api/routes/controller/controller.py" = ["UP012"]
"gns3server/api/routes/controller/dependencies/authentication.py" = ["S105", "S106"]
"gns3server/api/routes/controller/links.py" = ["E722"]
"gns3server/api/routes/controller/netmiko.py" = ["RUF100"]
"gns3server/api/routes/controller/nodes.py" = ["C901", "RUF019", "UP024"]
"gns3server/api/routes/controller/projects.py" = ["UP012"]
"gns3server/api/routes/controller/templates.py" = ["S324"]
"gns3server/api/routes/controller/users.py" = ["S105", "S106"]
"gns3server/api/routes/index.py" = ["RUF021"]
"gns3server/compute/base_node.py" = ["C901", "RUF019"]
"gns3server/compute/builtin/nodes/cloud.py" = ["E713"]
"gns3server/compute/docker/__init__.py" = ["B006", "C901"]
"gns3server/compute/docker/docker_vm.py" = ["B006", "C901", "E731", "RUF003", "RUF006", "S108", "UP031"]
"gns3server/compute/docker/iol_docker_vm.py" = ["RUF002", "S108"]
"gns3server/compute/docker/vendor_docker_vm.py" = ["RUF002", "S108"]
"gns3server/compute/dynamips/__init__.py" = ["C901"]
"gns3server/compute/dynamips/dynamips_hypervisor.py" = ["C901"]
"gns3server/compute/dynamips/nodes/router.py" = ["F522", "RUF006"]
"gns3server/compute/iou/iou_vm.py" = ["C901", "S108", "S324"]
"gns3server/compute/iou/utils/iou_export.py" = ["C901", "RUF003"]
"gns3server/compute/project.py" = ["DTZ006", "S324"]
"gns3server/compute/qemu/qemu_vm.py" = ["ASYNC220", "B009", "C901", "RUF003", "S603"]
"gns3server/compute/qemu/utils/ziputils.py" = ["RUF005", "UP031"]
"gns3server/compute/ubridge/ubridge_hypervisor.py" = ["C901"]
"gns3server/compute/virtualbox/virtualbox_vm.py" = ["C901", "RUF005", "S314"]
"gns3server/compute/vmware/__init__.py" = ["C901", "UP015"]
"gns3server/compute/vmware/vmware_vm.py" = ["C901"]
"gns3server/compute/vpcs/vpcs_vm.py" = ["B018"]
"gns3server/config.py" = ["B905", "C901"]
"gns3server/controller/__init__.py" = ["S311"]
"gns3server/controller/appliance_to_template.py" = ["C901"]
"gns3server/controller/compute.py" = ["B006", "C901"]
"gns3server/controller/drawing.py" = ["S314", "S324"]
"gns3server/controller/export_project.py" = ["C901", "DTZ006"]
"gns3server/controller/gns3vm/hyperv_gns3_vm.py" = ["RUF015", "S608"]
"gns3server/controller/gns3vm/virtualbox_gns3_vm.py" = ["C901"]
"gns3server/controller/import_project.py" = ["C901"]
"gns3server/controller/node.py" = ["C901", "PLW1641"]
"gns3server/controller/node_types.py" = ["W292"]
"gns3server/controller/ports/port_factory.py" = ["B020", "C901"]
"gns3server/controller/project.py" = ["ASYNC110", "C901", "RUF006", "RUF019"]
"gns3server/controller/topology.py" = ["C901"]
"gns3server/controller/udp_link.py" = ["C901"]
"gns3server/db/models/base.py" = ["UP031"]
"gns3server/db/repositories/llm_model_configs.py" = ["DTZ003", "RUF005", "RUF019"]
"gns3server/db/repositories/rbac.py" = ["C901"]
"gns3server/db/tasks.py" = ["B009", "RUF006", "RUF019", "UP004"]
"gns3server/db_migrations/versions/7ceeddd9c9a8_init.py" = ["W291"]
"gns3server/db_migrations/versions/ec4b7b198555_convert_pickletype_fields_to_json.py" = ["S301", "S608"]
"gns3server/logger.py" = ["PLW0127", "UP031"]
"gns3server/main.py" = ["UP031"]
"gns3server/schemas/controller/settings.py" = ["S105"]
"gns3server/schemas/controller/templates/docker_templates.py" = ["W292"]
"gns3server/schemas/controller/tokens.py" = ["S105"]
"gns3server/server.py" = ["DTZ011", "RUF006", "UP036"]
"gns3server/services/authentication.py" = ["S105"]
"gns3server/services/templates.py" = ["W292"]
"gns3server/utils/__init__.py" = ["S324", "UP031"]
"gns3server/utils/asyncio/__init__.py" = ["RUF006"]
"gns3server/utils/asyncio/aiozipstream.py" = ["C901", "UP031"]
"gns3server/utils/asyncio/raw_command_server.py" = ["B006"]
"gns3server/utils/asyncio/telnet_server.py" = ["RUF006"]
"gns3server/utils/images.py" = ["RUF021", "S324"]
"gns3server/utils/packet_filter_validation.py" = ["PLW1510", "S603", "S607", "W292"]
"gns3server/utils/picture.py" = ["C901"]
"gns3server/utils/port_allocator.py" = ["S324"]
"gns3server/utils/uninstall_ai_features.py" = ["PLW1510", "S603", "UP015"]
"gns3server/utils/vmnet.py" = ["S605", "S607"]
"gns3server/utils/websocket_to_websocket.py" = ["C901"]
"gns3server/utils/zipfile_zstd/__init__.py" = ["F403"]
"gns3server/version.py" = ["S607"]
"scripts/extract_mermaid.py" = ["C901", "PLW1510", "S603", "S607"]
"scripts/tag.py" = ["S603", "S607"]
"scripts/welcome.py" = ["C901", "E722", "PLW1510", "S108", "S112", "S603", "S605", "S606", "S607", "W291"]
"tests/agent/mcp/test_handlers.py" = ["B905"]
"tests/agent/mcp/test_tool_params.py" = ["C901"]
"tests/api/routes/controller/test_images.py" = ["S324", "W292"]
"tests/api/routes/controller/test_links.py" = ["RUF015", "W292"]
"tests/api/routes/controller/test_users.py" = ["F811"]
"tests/compute/docker/test_docker.py" = ["B018"]
"tests/compute/docker/test_docker_vm.py" = ["F811", "UP004"]
"tests/compute/docker/test_iol_docker_vm.py" = ["RUF003", "RUF015"]
"tests/compute/docker/test_vendor_docker_vm.py" = ["RUF015"]
"tests/compute/qemu/test_qemu_vm.py" = ["E741"]
"tests/compute/test_project.py" = ["RUF003", "RUF064", "S103"]
"tests/compute/virtualbox/test_virtualbox_manager.py" = ["B011"]
"tests/compute/vpcs/test_vpcs_vm.py" = ["RUF003"]
"tests/controller/gns3vm/test_vmware_gns3_vm.py" = ["UP015"]
"tests/controller/test_export_project.py" = ["E713"]
"tests/controller/test_import_project.py" = ["F811"]
"tests/controller/test_marker.py" = ["B006"]
"tests/controller/test_node.py" = ["E711", "F811"]
"tests/controller/test_project.py" = ["RUF015"]
"tests/controller/test_snapshot.py" = ["RUF015"]
"tests/controller/test_udp_link.py" = ["B006"]
"tests/test_server.py" = ["E722"]
"tests/test_topologies.py" = ["B011"]
"tests/test_utils.py" = ["F403", "F405"]
"tests/utils/test_asyncio.py" = ["B017"]
"tests/utils/test_packet_filter_validation.py" = ["W292"]
[tool.mypy]
files = ["gns3server"]
plugins = ["pydantic.mypy"]
# Third-party packages without type hints / stubs:
ignore_missing_imports = true
warn_unused_configs = true
warn_redundant_casts = true
warn_unused_ignores = true
strict_equality = true
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
[[tool.mypy.overrides]]
# Baseline: modules with existing type errors (error count at baseline time).
# Remove modules from this list one small PR at a time. Never add new ones.
module = [
"gns3server.agent", # 2
"gns3server.agent.gns3_copilot.agent.context_manager", # 5
"gns3server.agent.gns3_copilot.agent.model_factory", # 4
"gns3server.agent.gns3_copilot.agent_service", # 8
"gns3server.agent.gns3_copilot.chat_sessions_repository", # 8
"gns3server.agent.gns3_copilot.gns3_client.api_handlers", # 10
"gns3server.agent.gns3_copilot.gns3_client.connector_factory", # 1
"gns3server.agent.gns3_copilot.gns3_client.project_inventory", # 2
"gns3server.agent.gns3_copilot.skills.loader", # 1
"gns3server.agent.gns3_copilot.skills.manager", # 4
"gns3server.agent.gns3_copilot.tools_v2.config_tools_nornir", # 6
"gns3server.agent.gns3_copilot.tools_v2.display_tools_nornir", # 6
"gns3server.agent.gns3_copilot.tools_v2.gns3_packet_filter", # 1
"gns3server.agent.gns3_copilot.tools_v2.gns3_start_node", # 3
"gns3server.agent.gns3_copilot.tools_v2.gns3_stop_node", # 3
"gns3server.agent.gns3_copilot.tools_v2.gns3_suspend_node", # 3
"gns3server.agent.gns3_copilot.tools_v2.packet_analysis_tool", # 1
"gns3server.agent.gns3_copilot.tools_v2.vpcs_tools_netmiko", # 9
"gns3server.agent.gns3_copilot.utils.custom_netmiko.scripts.list_netmiko_telnet_devices", # 1
"gns3server.agent.gns3_copilot.utils.message_converters", # 2
"gns3server.agent.gns3_copilot.utils.parse_tool_content", # 1
"gns3server.agent.mcp", # 34
"gns3server.agent.mcp.appliances", # 1
"gns3server.agent.web_wireshark.docker_client", # 5
"gns3server.agent.web_wireshark.manage_wireshark", # 1
"gns3server.agent.web_wireshark.manager", # 9
"gns3server.agent.web_wireshark.stats", # 4
"gns3server.api.routes.compute.atm_switch_nodes", # 9
"gns3server.api.routes.compute.capabilities", # 1
"gns3server.api.routes.compute.cloud_nodes", # 14
"gns3server.api.routes.compute.compute", # 1
"gns3server.api.routes.compute.dependencies.authentication", # 3
"gns3server.api.routes.compute.docker_nodes", # 26
"gns3server.api.routes.compute.dynamips_nodes", # 9
"gns3server.api.routes.compute.ethernet_hub_nodes", # 9
"gns3server.api.routes.compute.ethernet_switch_nodes", # 16
"gns3server.api.routes.compute.frame_relay_switch_nodes", # 9
"gns3server.api.routes.compute.iou_nodes", # 15
"gns3server.api.routes.compute.nat_nodes", # 10
"gns3server.api.routes.compute.notifications", # 4
"gns3server.api.routes.compute.projects", # 7
"gns3server.api.routes.compute.qemu_nodes", # 18
"gns3server.api.routes.compute.virtualbox_nodes", # 20
"gns3server.api.routes.compute.vmware_nodes", # 10
"gns3server.api.routes.compute.vpcs_nodes", # 9
"gns3server.api.routes.controller.acl", # 5
"gns3server.api.routes.controller.api_keys", # 1
"gns3server.api.routes.controller.chat", # 1
"gns3server.api.routes.controller.computes", # 6
"gns3server.api.routes.controller.controller", # 10
"gns3server.api.routes.controller.dependencies.authentication", # 11
"gns3server.api.routes.controller.dependencies.database", # 2
"gns3server.api.routes.controller.drawings", # 1
"gns3server.api.routes.controller.groups", # 6
"gns3server.api.routes.controller.images", # 9
"gns3server.api.routes.controller.links", # 27
"gns3server.api.routes.controller.llm_model_configs", # 32
"gns3server.api.routes.controller.nodes", # 13
"gns3server.api.routes.controller.pools", # 8
"gns3server.api.routes.controller.privileges", # 1
"gns3server.api.routes.controller.projects", # 16
"gns3server.api.routes.controller.roles", # 5
"gns3server.api.routes.controller.snapshots", # 1
"gns3server.api.routes.controller.templates", # 10
"gns3server.api.routes.controller.users", # 14
"gns3server.api.routes.index", # 1
"gns3server.api.server", # 2
"gns3server.compute.docker.docker_vm", # 3
"gns3server.compute.docker.iol_docker_vm", # 3
"gns3server.compute.dynamips.nodes.router", # 2
"gns3server.compute.iou.iou_vm", # 4
"gns3server.compute.iou.utils.iou_export", # 2
"gns3server.compute.iou.utils.iou_import", # 2
"gns3server.compute.project", # 1
"gns3server.compute.qemu.qemu_vm", # 2
"gns3server.compute.virtualbox.virtualbox_vm", # 1
"gns3server.compute.vmware.vmware_vm", # 1
"gns3server.compute.vpcs.vpcs_vm", # 2
"gns3server.config", # 1
"gns3server.controller.appliance", # 2
"gns3server.controller.appliance_manager", # 5
"gns3server.controller.compute", # 2
"gns3server.controller.project", # 2
"gns3server.controller.topology", # 1
"gns3server.db.models.acl", # 1
"gns3server.db.models.images", # 1
"gns3server.db.models.pools", # 1
"gns3server.db.models.privileges", # 2
"gns3server.db.models.roles", # 1
"gns3server.db.models.templates", # 22
"gns3server.db.models.users", # 3
"gns3server.db.repositories.api_keys", # 8
"gns3server.db.repositories.computes", # 10
"gns3server.db.repositories.images", # 14
"gns3server.db.repositories.llm_model_configs", # 32
"gns3server.db.repositories.pools", # 11
"gns3server.db.repositories.rbac", # 14
"gns3server.db.repositories.templates", # 6
"gns3server.db.repositories.users", # 12
"gns3server.db.tasks", # 12
"gns3server.db_migrations.env", # 1
"gns3server.schemas.compute.atm_switch_nodes", # 5
"gns3server.schemas.compute.cloud_nodes", # 1
"gns3server.schemas.compute.docker_nodes", # 2
"gns3server.schemas.compute.dynamips_nodes", # 1
"gns3server.schemas.compute.frame_relay_switch_nodes", # 5
"gns3server.schemas.compute.iou_nodes", # 3
"gns3server.schemas.compute.nat_nodes", # 1
"gns3server.schemas.compute.qemu_nodes", # 1
"gns3server.schemas.compute.virtualbox_nodes", # 2
"gns3server.schemas.compute.vmware_nodes", # 3
"gns3server.schemas.compute.vpcs_nodes", # 1
"gns3server.schemas.controller.appliances", # 1
"gns3server.schemas.controller.computes", # 6
"gns3server.schemas.controller.nodes", # 3
"gns3server.schemas.controller.projects", # 2
"gns3server.schemas.controller.settings", # 3
"gns3server.schemas.controller.templates.docker_templates", # 1
"gns3server.schemas.controller.templates.dynamips_templates", # 17
"gns3server.schemas.controller.templates.iou_templates", # 1
"gns3server.schemas.controller.templates.virtualbox_templates", # 1
"gns3server.schemas.controller.templates.vmware_templates", # 1
"gns3server.schemas.qemu_disk_image", # 2
"gns3server.services.authentication", # 5
"gns3server.services.computes", # 4
"gns3server.services.templates", # 18
"gns3server.utils.asyncio.aiozipstream", # 8
"gns3server.utils.asyncio.embed_shell", # 1
"gns3server.utils.encryption", # 2
"gns3server.utils.http_client", # 4
"gns3server.utils.images", # 4
"gns3server.utils.packet_filter_validation", # 16
"gns3server.utils.websocket_to_websocket", # 12
"gns3server.utils.zipfile_zstd", # 2
"gns3server.utils.zipfile_zstd._patcher", # 1
"gns3server.utils.zipfile_zstd._zipfile", # 5
]
ignore_errors = true