glpi-python-client 0.5.0__tar.gz → 0.6.0__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.
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/.gitignore +1 -1
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/CHANGELOG.md +89 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/CONTRIBUTING.md +17 -1
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/PKG-INFO +9 -10
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/README.md +1 -1
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/docs/api_reference.rst +131 -10
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/docs/conf.py +1 -5
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/docs/installation.rst +1 -1
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/docs/publishing_rtd.rst +1 -1
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/docs/user_guide.rst +239 -3
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/__init__.py +43 -1
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/auth/_v1_session.py +3 -3
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/auth/auth.py +3 -3
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/_base_client.py +1 -7
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/api/__init__.py +13 -3
- glpi_python_client-0.6.0/glpi_python_client/_async/clients/api/assets/__init__.py +7 -0
- glpi_python_client-0.6.0/glpi_python_client/_async/clients/api/assets/_computer.py +427 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/api/dropdowns/__init__.py +4 -1
- glpi_python_client-0.6.0/glpi_python_client/_async/clients/api/dropdowns/_contract_type.py +220 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/api/management/__init__.py +2 -1
- glpi_python_client-0.6.0/glpi_python_client/_async/clients/api/management/_contract.py +411 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/client.py +7 -6
- {glpi_python_client-0.5.0/glpi_python_client/_sync → glpi_python_client-0.6.0/glpi_python_client/_async}/clients/commons/_constants.py +9 -1
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/auth/_v1_session.py +3 -3
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/auth/auth.py +3 -3
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/_base_client.py +1 -7
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/api/__init__.py +13 -3
- glpi_python_client-0.6.0/glpi_python_client/_sync/clients/api/assets/__init__.py +7 -0
- glpi_python_client-0.6.0/glpi_python_client/_sync/clients/api/assets/_computer.py +427 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/api/dropdowns/__init__.py +4 -1
- glpi_python_client-0.6.0/glpi_python_client/_sync/clients/api/dropdowns/_contract_type.py +220 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/api/management/__init__.py +2 -1
- glpi_python_client-0.6.0/glpi_python_client/_sync/clients/api/management/_contract.py +411 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/client.py +7 -6
- {glpi_python_client-0.5.0/glpi_python_client/_async → glpi_python_client-0.6.0/glpi_python_client/_sync}/clients/commons/_constants.py +9 -1
- glpi_python_client-0.6.0/glpi_python_client/content/conversion.py +675 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/__init__.py +45 -1
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/api_schema/__init__.py +1 -1
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/api_schema/_content.py +9 -10
- glpi_python_client-0.6.0/glpi_python_client/models/api_schema/assets/__init__.py +25 -0
- glpi_python_client-0.6.0/glpi_python_client/models/api_schema/assets/_computer.py +257 -0
- glpi_python_client-0.6.0/glpi_python_client/models/api_schema/assets/_contract_item.py +102 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/api_schema/dropdowns/__init__.py +10 -0
- glpi_python_client-0.6.0/glpi_python_client/models/api_schema/dropdowns/_contract_type.py +100 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/api_schema/enums.py +14 -0
- glpi_python_client-0.6.0/glpi_python_client/models/api_schema/management/__init__.py +35 -0
- glpi_python_client-0.6.0/glpi_python_client/models/api_schema/management/_contract.py +328 -0
- glpi_python_client-0.6.0/glpi_python_client/models/api_schema/management/_contract_cost.py +139 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/custom_schema/_ticket_context.py +18 -6
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/pyproject.toml +15 -12
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/skills/README.md +3 -1
- glpi_python_client-0.6.0/skills/glpi-asset-workflow/SKILL.md +89 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/skills/glpi-client-setup/SKILL.md +2 -2
- glpi_python_client-0.6.0/skills/glpi-contract-workflow/SKILL.md +123 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/skills/glpi-document-workflow/SKILL.md +2 -2
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/skills/glpi-knowledge-base/SKILL.md +2 -2
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/skills/glpi-plugin-fields/SKILL.md +2 -2
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/skills/glpi-reporting-and-context/SKILL.md +2 -2
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/skills/glpi-team-members/SKILL.md +2 -2
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/skills/glpi-ticket-timeline/SKILL.md +4 -3
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/skills/glpi-ticket-workflow/SKILL.md +4 -3
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/skills/glpi-user-location-provisioning/SKILL.md +2 -2
- glpi_python_client-0.5.0/glpi_python_client/content/conversion.py +0 -729
- glpi_python_client-0.5.0/glpi_python_client/models/api_schema/management/__init__.py +0 -15
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/.pre-commit-config.yaml +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/.readthedocs.yaml +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/LICENSE +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/docs/_static/.gitkeep +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/docs/development.md +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/docs/development_rtd.rst +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/docs/index.rst +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/docs/publishing.md +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/docs/sponsoring.rst +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/_concurrency.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/_testing.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/auth/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/api/administration/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/api/administration/_entity.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/api/administration/_user.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/api/assistance/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/api/assistance/_team.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/api/assistance/_ticket.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/api/assistance/timeline/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/api/assistance/timeline/_document.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/api/assistance/timeline/_followup.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/api/assistance/timeline/_solution.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/api/assistance/timeline/_task.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/api/dropdowns/_location.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/api/knowledgebase/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/api/knowledgebase/_article.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/api/knowledgebase/_category.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/api/knowledgebase/_comment.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/api/knowledgebase/_revision.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/api/management/_document.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/api/plugins/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/api/plugins/_fields.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/commons/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/commons/_config.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/commons/_filters.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/commons/_http.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/commons/_payloads.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/commons/_transport.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/custom/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/custom/_statistics.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_async/clients/custom/_ticket_context.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_errors.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/_concurrency.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/_testing.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/auth/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/api/administration/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/api/administration/_entity.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/api/administration/_user.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/api/assistance/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/api/assistance/_team.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/api/assistance/_ticket.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/api/assistance/timeline/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/api/assistance/timeline/_document.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/api/assistance/timeline/_followup.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/api/assistance/timeline/_solution.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/api/assistance/timeline/_task.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/api/dropdowns/_location.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/api/knowledgebase/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/api/knowledgebase/_article.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/api/knowledgebase/_category.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/api/knowledgebase/_comment.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/api/knowledgebase/_revision.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/api/management/_document.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/api/plugins/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/api/plugins/_fields.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/commons/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/commons/_config.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/commons/_filters.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/commons/_http.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/commons/_payloads.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/commons/_transport.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/custom/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/custom/_statistics.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/_sync/clients/custom/_ticket_context.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/content/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/_base.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/api_schema/_common.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/api_schema/administration/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/api_schema/administration/_entity.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/api_schema/administration/_user.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/api_schema/assistance/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/api_schema/assistance/_team.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/api_schema/assistance/_ticket.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/api_schema/assistance/timeline/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/api_schema/assistance/timeline/_document.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/api_schema/assistance/timeline/_followup.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/api_schema/assistance/timeline/_solution.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/api_schema/assistance/timeline/_task.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/api_schema/dropdowns/_location.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/api_schema/knowledgebase/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/api_schema/knowledgebase/_article.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/api_schema/knowledgebase/_category.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/api_schema/knowledgebase/_comment.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/api_schema/knowledgebase/_revision.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/api_schema/management/_document.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/api_schema/plugins/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/api_schema/plugins/_fields.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/models/custom_schema/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/py.typed +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/rsql.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/testing/__init__.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/testing/fixtures.py +0 -0
- {glpi_python_client-0.5.0 → glpi_python_client-0.6.0}/glpi_python_client/testing/utils.py +0 -0
|
@@ -4,6 +4,95 @@ All notable changes to this project are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
6
|
|
|
7
|
+
## 0.6.0 — 2026-10-01
|
|
8
|
+
|
|
9
|
+
### Changed (breaking)
|
|
10
|
+
|
|
11
|
+
- **Python 3.10 is no longer supported; 3.11 is the minimum.** The
|
|
12
|
+
`typing-extensions` and `tomli` backports it needed are dropped.
|
|
13
|
+
- **Content conversion is rebuilt on three libraries: markdownify,
|
|
14
|
+
mdformat and cmark-gfm.** `from_transport` reads GLPI's HTML with
|
|
15
|
+
`markdownify`, and `mdformat` re-renders that Markdown from its syntax
|
|
16
|
+
tree, so it keeps only the escapes CommonMark needs. `to_transport`
|
|
17
|
+
renders through `cmark-gfm`, the GitHub reference implementation, in
|
|
18
|
+
place of python-markdown. A thin layer of glue sits on top. Measured on
|
|
19
|
+
346 real bodies sampled from a GLPI 11 instance:
|
|
20
|
+
- 322 display the same after a round trip, against 299 before;
|
|
21
|
+
- 344 read back as the same Markdown, against 240.
|
|
22
|
+
|
|
23
|
+
Of 205 realistic caller-written Markdown documents, all 205 survive
|
|
24
|
+
Markdown → HTML → Markdown with the same display.
|
|
25
|
+
- **Markdown is rendered as CommonMark with GFM tables.** A newline is a
|
|
26
|
+
line break, as `nl2br` made it before. Raw HTML passes through.
|
|
27
|
+
Differences you may see in Markdown you write:
|
|
28
|
+
- a list or a table written straight after a line now starts a list or a
|
|
29
|
+
table, where python-markdown wanted a blank line first;
|
|
30
|
+
- lists nested by two or three spaces nest;
|
|
31
|
+
- `1)` starts a numbered list;
|
|
32
|
+
- `#Important`, with no space, is text rather than a heading;
|
|
33
|
+
- `*a **b** c*` keeps its bold;
|
|
34
|
+
- a backslash ending a line is a line break, so write `C:\Temp\` at the
|
|
35
|
+
end of a line as `` `C:\Temp\` ``;
|
|
36
|
+
- `<word>` is read as an HTML tag, so put a placeholder such as `<login>`
|
|
37
|
+
in backticks.
|
|
38
|
+
- **`.content` is spelled as canonical CommonMark.** A line break reads
|
|
39
|
+
back as `\` and a newline, a nested list is indented by its bullet's
|
|
40
|
+
width, and a table comes back unpadded. Text that would otherwise read as
|
|
41
|
+
syntax is escaped: `__init__` reads `\_\_init\_\_`, and a `* point` line
|
|
42
|
+
reads `\* point`. Stored digests of `.content` change once.
|
|
43
|
+
- **A plain-text body is literal text on the read path.** A value with no
|
|
44
|
+
HTML element used to come back verbatim and be rendered as Markdown. It is
|
|
45
|
+
now read as GLPI displays it, its lines as lines.
|
|
46
|
+
`GlpiContentConverter.from_transport` takes `plain_text_is_markdown`.
|
|
47
|
+
`True` is what the write models' validator passes: caller-authored
|
|
48
|
+
Markdown passes verbatim unless it starts with an HTML tag, so Markdown
|
|
49
|
+
carrying an inline `<br>` or `<kbd>` stays Markdown.
|
|
50
|
+
- **Dependencies.**
|
|
51
|
+
- Added: `cmarkgfm>=2025.10` (compiled wheels for CPython 3.11–3.14 on
|
|
52
|
+
Linux, macOS and Windows), `mdformat>=0.7.22,<0.8`,
|
|
53
|
+
`mdformat-tables>=1.0` and `markdown-it-py>=3.0`.
|
|
54
|
+
- Dropped: `markdown`. python-markdown 3.11 had broken the previous
|
|
55
|
+
reader.
|
|
56
|
+
- Raised: `beautifulsoup4>=4.15`, which fixed the parser defect that
|
|
57
|
+
dropped the text after a `<br />` in a body that also held a bare
|
|
58
|
+
`<br>`. That removes the workaround.
|
|
59
|
+
|
|
60
|
+
### Fixed
|
|
61
|
+
|
|
62
|
+
- **Literal text came back as Markdown syntax.** These now read back as the
|
|
63
|
+
text a user typed:
|
|
64
|
+
- `\serveur\compta`, which had lost a backslash;
|
|
65
|
+
- `__init__` and `______`, which had become bold;
|
|
66
|
+
- a `-----` line under text, which had made a heading;
|
|
67
|
+
- `* point` and `> merci` lines, which had become a list and a quote;
|
|
68
|
+
- `[1]: https://...`, which had been consumed as a reference definition;
|
|
69
|
+
- a `|` in a table cell, which had dropped the rest of the row.
|
|
70
|
+
- **A table nested in a table cell lost all its text.** That is the usual
|
|
71
|
+
layout of an e-mail signature. The inner table is now written as its
|
|
72
|
+
cells' text, its line breaks kept as `<br>`.
|
|
73
|
+
- **Nested lists flattened on the first write.** Nested items, the text
|
|
74
|
+
after a nested list, and numbering, `start` included, survive.
|
|
75
|
+
- `<script>`, `<style>` and `<title>` bodies no longer leak into the text.
|
|
76
|
+
- A blank line inside a paragraph (`<br><br>`, or Outlook's
|
|
77
|
+
`<br> <br>`) is kept.
|
|
78
|
+
- A label in bold right before a figure, as in `<b>Total:</b>12`, keeps its
|
|
79
|
+
bold.
|
|
80
|
+
- A code fence keeps its language, and a `|` inside code in a table cell no
|
|
81
|
+
longer splits the row.
|
|
82
|
+
- A long body converts in linear time, and a body nested deeper than the
|
|
83
|
+
stack is read as its text instead of raising.
|
|
84
|
+
|
|
85
|
+
### Known limitations
|
|
86
|
+
|
|
87
|
+
- A Markdown table needs a header row and the same number of cells in every
|
|
88
|
+
row. A header-less HTML table gains an empty header row, and a row that
|
|
89
|
+
spans the table gains empty cells.
|
|
90
|
+
- Struck-through text is kept as raw `<s>`, since CommonMark has no
|
|
91
|
+
strikethrough.
|
|
92
|
+
- Literal text that looks like syntax is sometimes escaped where
|
|
93
|
+
CommonMark would not need it, for example `5\*3` or `x \<= y`. It
|
|
94
|
+
displays as typed.
|
|
95
|
+
|
|
7
96
|
## 0.5.0 — 2026-09-08
|
|
8
97
|
|
|
9
98
|
### Fixed
|
|
@@ -38,7 +38,7 @@ python -m sphinx -W --keep-going -b html docs docs/_build/html
|
|
|
38
38
|
|
|
39
39
|
## GitHub Actions
|
|
40
40
|
|
|
41
|
-
- `.github/workflows/ci.yml` runs tests for Python 3.
|
|
41
|
+
- `.github/workflows/ci.yml` runs tests for Python 3.11 through 3.14 on pull
|
|
42
42
|
requests and pushes to `main`.
|
|
43
43
|
- The same workflow runs `ruff`, `mypy`, and a warning-free Sphinx build on
|
|
44
44
|
Python 3.12.
|
|
@@ -63,3 +63,19 @@ python -m sphinx -W --keep-going -b html docs docs/_build/html
|
|
|
63
63
|
library core.
|
|
64
64
|
- Add tests for payload serialization and response normalization when adding
|
|
65
65
|
endpoints.
|
|
66
|
+
|
|
67
|
+
### The GLPI OpenAPI contract
|
|
68
|
+
|
|
69
|
+
The models under `glpi_python_client/models/api_schema/` mirror
|
|
70
|
+
`components.schemas.*` from the GLPI High-Level REST API document,
|
|
71
|
+
including which fields are `readOnly`. That document is not committed —
|
|
72
|
+
it is ~14 MB and instance-specific. Fetch your instance's copy to the
|
|
73
|
+
path the models cite:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
curl -sk "<your GLPI base>/api.php/v2.3/doc.json" -o docs/api_contract/api.json
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`docs/api_contract/` is gitignored. Nothing in CI checks the models
|
|
80
|
+
against it, so when you add or change a model, diff it against the
|
|
81
|
+
contract by hand.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: glpi-python-client
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: A typed Python client for GLPI ITSM APIs.
|
|
5
5
|
Project-URL: Homepage, https://github.com/baraline/glpi_python_client
|
|
6
6
|
Project-URL: Documentation, https://glpi-python-client.readthedocs.io/en/latest/
|
|
@@ -15,7 +15,6 @@ Classifier: Intended Audience :: Developers
|
|
|
15
15
|
Classifier: License :: OSI Approved :: MIT License
|
|
16
16
|
Classifier: Operating System :: OS Independent
|
|
17
17
|
Classifier: Programming Language :: Python :: 3
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.11
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.13
|
|
@@ -23,16 +22,18 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
23
22
|
Classifier: Topic :: Internet :: WWW/HTTP
|
|
24
23
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
25
24
|
Classifier: Typing :: Typed
|
|
26
|
-
Requires-Python: >=3.
|
|
27
|
-
Requires-Dist: beautifulsoup4>=4.
|
|
25
|
+
Requires-Python: >=3.11
|
|
26
|
+
Requires-Dist: beautifulsoup4>=4.15
|
|
27
|
+
Requires-Dist: cmarkgfm>=2025.10
|
|
28
28
|
Requires-Dist: httpx>=0.28
|
|
29
29
|
Requires-Dist: lxml>=4.9
|
|
30
|
-
Requires-Dist: markdown>=3.
|
|
31
|
-
Requires-Dist: markdownify>=
|
|
30
|
+
Requires-Dist: markdown-it-py>=3.0
|
|
31
|
+
Requires-Dist: markdownify>=1.2
|
|
32
|
+
Requires-Dist: mdformat-tables>=1.0
|
|
33
|
+
Requires-Dist: mdformat<0.8,>=0.7.22
|
|
32
34
|
Requires-Dist: pydantic>=2.8
|
|
33
35
|
Requires-Dist: sniffio>=1.3
|
|
34
36
|
Requires-Dist: tenacity>=8.2
|
|
35
|
-
Requires-Dist: typing-extensions>=4.7; python_version < '3.11'
|
|
36
37
|
Requires-Dist: tzdata>=2024.1; platform_system == 'Windows'
|
|
37
38
|
Provides-Extra: dev
|
|
38
39
|
Requires-Dist: build>=1.2; extra == 'dev'
|
|
@@ -45,7 +46,6 @@ Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
|
45
46
|
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
46
47
|
Requires-Dist: sphinx-rtd-theme>=2.0; extra == 'dev'
|
|
47
48
|
Requires-Dist: sphinx<8.2,>=7.2; extra == 'dev'
|
|
48
|
-
Requires-Dist: tomli>=2.0; (python_version < '3.11') and extra == 'dev'
|
|
49
49
|
Requires-Dist: twine>=5.1; extra == 'dev'
|
|
50
50
|
Requires-Dist: unasync>=0.6; extra == 'dev'
|
|
51
51
|
Requires-Dist: vulture>=2.11; extra == 'dev'
|
|
@@ -53,7 +53,6 @@ Provides-Extra: docs
|
|
|
53
53
|
Requires-Dist: numpydoc>=1.8; extra == 'docs'
|
|
54
54
|
Requires-Dist: sphinx-rtd-theme>=2.0; extra == 'docs'
|
|
55
55
|
Requires-Dist: sphinx<8.2,>=7.2; extra == 'docs'
|
|
56
|
-
Requires-Dist: tomli>=2.0; (python_version < '3.11') and extra == 'docs'
|
|
57
56
|
Description-Content-Type: text/markdown
|
|
58
57
|
|
|
59
58
|
# glpi-python-client
|
|
@@ -61,7 +60,7 @@ Description-Content-Type: text/markdown
|
|
|
61
60
|
[](https://github.com/baraline/glpi_python_client/actions/workflows/ci.yml)
|
|
62
61
|
[](https://codecov.io/gh/baraline/glpi_python_client)
|
|
63
62
|
[](LICENSE)
|
|
64
|
-
[](https://github.com/baraline/glpi_python_client)
|
|
65
64
|
[](https://glpi-python-client.readthedocs.io/en/latest/)
|
|
66
65
|
|
|
67
66
|
`glpi-python-client` is a typed Python client for the GLPI REST API.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://github.com/baraline/glpi_python_client/actions/workflows/ci.yml)
|
|
4
4
|
[](https://codecov.io/gh/baraline/glpi_python_client)
|
|
5
5
|
[](LICENSE)
|
|
6
|
-
[](https://github.com/baraline/glpi_python_client)
|
|
7
7
|
[](https://glpi-python-client.readthedocs.io/en/latest/)
|
|
8
8
|
|
|
9
9
|
`glpi-python-client` is a typed Python client for the GLPI REST API.
|
|
@@ -113,18 +113,19 @@ conversion happens, which buys two things: listing records costs nothing
|
|
|
113
113
|
per body, and a body that cannot be converted no longer stops the rest of
|
|
114
114
|
its page being read.
|
|
115
115
|
|
|
116
|
+
The Markdown is CommonMark with GFM tables, rendered by cmark-gfm. It
|
|
117
|
+
spells a body's text as literal text -- ``\_\_init\_\_``, ``\\\serveur``,
|
|
118
|
+
``\# pas un titre`` -- so rendering it displays what GLPI displayed and
|
|
119
|
+
reading that back gives the same Markdown. A write model keeps the caller's
|
|
120
|
+
Markdown verbatim unless it starts with an HTML tag. See
|
|
121
|
+
:ref:`content-conversion`.
|
|
122
|
+
|
|
116
123
|
Very deeply nested HTML is the case worth knowing about.
|
|
117
124
|
``markdownify`` walks the document recursively and runs out of stack at
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
What is lost is structure rather than words — link targets and image alt
|
|
123
|
-
text, code fencing and ``<pre>`` indentation, `` `` alignment.
|
|
124
|
-
Because the budget is the stack left when the conversion starts, the
|
|
125
|
-
same body can convert from one call site and degrade from a deeper one.
|
|
126
|
-
Anything else that goes wrong in either direction raises
|
|
127
|
-
:class:`GlpiContentError`.
|
|
125
|
+
a few hundred levels of nesting. The converter attempts the conversion
|
|
126
|
+
and, if the walk does not fit, reads the body's text instead, a line per
|
|
127
|
+
block: the words survive, the structure does not. Anything else that goes
|
|
128
|
+
wrong in either direction raises :class:`GlpiContentError`.
|
|
128
129
|
|
|
129
130
|
Because the conversion is cached on first read, a read model should be
|
|
130
131
|
treated as immutable afterwards: assigning to ``content_html``, or
|
|
@@ -499,6 +500,121 @@ The companion mixin methods are exposed on :class:`GlpiClient` /
|
|
|
499
500
|
:undoc-members:
|
|
500
501
|
:show-inheritance:
|
|
501
502
|
|
|
503
|
+
Computers
|
|
504
|
+
---------
|
|
505
|
+
|
|
506
|
+
.. autoclass:: GetComputer
|
|
507
|
+
:members:
|
|
508
|
+
:undoc-members:
|
|
509
|
+
:show-inheritance:
|
|
510
|
+
|
|
511
|
+
.. autoclass:: PostComputer
|
|
512
|
+
:members:
|
|
513
|
+
:undoc-members:
|
|
514
|
+
:show-inheritance:
|
|
515
|
+
|
|
516
|
+
.. autoclass:: PatchComputer
|
|
517
|
+
:members:
|
|
518
|
+
:undoc-members:
|
|
519
|
+
:show-inheritance:
|
|
520
|
+
|
|
521
|
+
.. autoclass:: DeleteComputer
|
|
522
|
+
:members:
|
|
523
|
+
:undoc-members:
|
|
524
|
+
:show-inheritance:
|
|
525
|
+
|
|
526
|
+
Computer Contract Links
|
|
527
|
+
-----------------------
|
|
528
|
+
|
|
529
|
+
.. autoclass:: GetContractItem
|
|
530
|
+
:members:
|
|
531
|
+
:undoc-members:
|
|
532
|
+
:show-inheritance:
|
|
533
|
+
|
|
534
|
+
.. autoclass:: PostContractItem
|
|
535
|
+
:members:
|
|
536
|
+
:undoc-members:
|
|
537
|
+
:show-inheritance:
|
|
538
|
+
|
|
539
|
+
.. autoclass:: PatchContractItem
|
|
540
|
+
:members:
|
|
541
|
+
:undoc-members:
|
|
542
|
+
:show-inheritance:
|
|
543
|
+
|
|
544
|
+
.. autoclass:: DeleteContractItem
|
|
545
|
+
:members:
|
|
546
|
+
:undoc-members:
|
|
547
|
+
:show-inheritance:
|
|
548
|
+
|
|
549
|
+
Contracts
|
|
550
|
+
---------
|
|
551
|
+
|
|
552
|
+
.. autoclass:: GetContract
|
|
553
|
+
:members:
|
|
554
|
+
:undoc-members:
|
|
555
|
+
:show-inheritance:
|
|
556
|
+
|
|
557
|
+
.. autoclass:: PostContract
|
|
558
|
+
:members:
|
|
559
|
+
:undoc-members:
|
|
560
|
+
:show-inheritance:
|
|
561
|
+
|
|
562
|
+
.. autoclass:: PatchContract
|
|
563
|
+
:members:
|
|
564
|
+
:undoc-members:
|
|
565
|
+
:show-inheritance:
|
|
566
|
+
|
|
567
|
+
.. autoclass:: DeleteContract
|
|
568
|
+
:members:
|
|
569
|
+
:undoc-members:
|
|
570
|
+
:show-inheritance:
|
|
571
|
+
|
|
572
|
+
Contract Costs
|
|
573
|
+
--------------
|
|
574
|
+
|
|
575
|
+
.. autoclass:: GetContractCost
|
|
576
|
+
:members:
|
|
577
|
+
:undoc-members:
|
|
578
|
+
:show-inheritance:
|
|
579
|
+
|
|
580
|
+
.. autoclass:: PostContractCost
|
|
581
|
+
:members:
|
|
582
|
+
:undoc-members:
|
|
583
|
+
:show-inheritance:
|
|
584
|
+
|
|
585
|
+
.. autoclass:: PatchContractCost
|
|
586
|
+
:members:
|
|
587
|
+
:undoc-members:
|
|
588
|
+
:show-inheritance:
|
|
589
|
+
|
|
590
|
+
.. autoclass:: DeleteContractCost
|
|
591
|
+
:members:
|
|
592
|
+
:undoc-members:
|
|
593
|
+
:show-inheritance:
|
|
594
|
+
|
|
595
|
+
Contract Types
|
|
596
|
+
--------------
|
|
597
|
+
|
|
598
|
+
.. autoclass:: GetContractType
|
|
599
|
+
:members:
|
|
600
|
+
:undoc-members:
|
|
601
|
+
:show-inheritance:
|
|
602
|
+
|
|
603
|
+
.. autoclass:: PostContractType
|
|
604
|
+
:members:
|
|
605
|
+
:undoc-members:
|
|
606
|
+
:show-inheritance:
|
|
607
|
+
|
|
608
|
+
.. autoclass:: PatchContractType
|
|
609
|
+
:members:
|
|
610
|
+
:undoc-members:
|
|
611
|
+
:show-inheritance:
|
|
612
|
+
|
|
613
|
+
.. autoclass:: DeleteContractType
|
|
614
|
+
:members:
|
|
615
|
+
:undoc-members:
|
|
616
|
+
:show-inheritance:
|
|
617
|
+
|
|
502
618
|
Enums
|
|
503
619
|
-----
|
|
504
620
|
|
|
@@ -547,6 +663,11 @@ Enums
|
|
|
547
663
|
:undoc-members:
|
|
548
664
|
:show-inheritance:
|
|
549
665
|
|
|
666
|
+
.. autoclass:: GlpiContractRenewalType
|
|
667
|
+
:members:
|
|
668
|
+
:undoc-members:
|
|
669
|
+
:show-inheritance:
|
|
670
|
+
|
|
550
671
|
Package Metadata
|
|
551
672
|
----------------
|
|
552
673
|
|
|
@@ -5,11 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
from datetime import date
|
|
6
6
|
from importlib.metadata import PackageNotFoundError, version
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
|
|
9
|
-
try:
|
|
10
|
-
from tomllib import loads as toml_loads
|
|
11
|
-
except ModuleNotFoundError:
|
|
12
|
-
from tomli import loads as toml_loads
|
|
8
|
+
from tomllib import loads as toml_loads
|
|
13
9
|
|
|
14
10
|
|
|
15
11
|
def _read_project_version() -> str:
|
|
@@ -4,7 +4,7 @@ Installation
|
|
|
4
4
|
Requirements
|
|
5
5
|
------------
|
|
6
6
|
|
|
7
|
-
``glpi-python-client`` supports Python 3.
|
|
7
|
+
``glpi-python-client`` supports Python 3.11 and newer. Runtime dependencies are installed
|
|
8
8
|
from the package metadata and include ``httpx``, ``tenacity``,
|
|
9
9
|
``beautifulsoup4``, ``lxml``, and ``pydantic``.
|
|
10
10
|
|
|
@@ -92,7 +92,7 @@ GitHub Actions and Read the Docs
|
|
|
92
92
|
The repository ships with two GitHub Actions workflows:
|
|
93
93
|
|
|
94
94
|
* ``.github/workflows/ci.yml`` runs on pull requests and pushes to ``main``.
|
|
95
|
-
It executes ``pytest`` on Python 3.
|
|
95
|
+
It executes ``pytest`` on Python 3.11 through 3.14, then runs ``ruff``,
|
|
96
96
|
``mypy``, and the Sphinx build on Python 3.12.
|
|
97
97
|
* ``.github/workflows/release.yml`` runs on published GitHub releases. It
|
|
98
98
|
repeats the quality checks, builds the source and wheel distributions,
|
|
@@ -38,7 +38,7 @@ The guide is split into the following sections:
|
|
|
38
38
|
throwaway GLPI instance to follow along.
|
|
39
39
|
4. **GLPI API interface** — the contract-aligned helpers that map
|
|
40
40
|
one-to-one to GLPI v2 endpoints (tickets, timeline, team members,
|
|
41
|
-
users, locations, entities, documents).
|
|
41
|
+
users, locations, entities, documents, computers, contracts).
|
|
42
42
|
5. **Added functionalities** — helpers built on top of the API mixins:
|
|
43
43
|
the ``Fields`` plugin custom-field helpers, the aggregated ticket
|
|
44
44
|
context view, and the reporting helpers.
|
|
@@ -580,6 +580,211 @@ Example output::
|
|
|
580
580
|
the client (``v1_base_url`` and ``v1_user_token``) because the GLPI v2
|
|
581
581
|
contract does not advertise a binary upload endpoint.
|
|
582
582
|
|
|
583
|
+
Assets
|
|
584
|
+
~~~~~~
|
|
585
|
+
|
|
586
|
+
The asset mixins map to ``/Assets/*``. GLPI models roughly two dozen
|
|
587
|
+
asset itemtypes (computers, monitors, printers, network equipment, and
|
|
588
|
+
so on), and this client currently implements only ``Computer`` -- there
|
|
589
|
+
is no ``search_monitors`` or ``get_printer``. Treat ``Computer`` as the
|
|
590
|
+
one supported asset type rather than a stand-in for the rest of the
|
|
591
|
+
family.
|
|
592
|
+
|
|
593
|
+
``search_ / get_ / create_ / update_ / delete_`` follow the same shape
|
|
594
|
+
as the other resources, with ``iter_search_computers`` for streaming
|
|
595
|
+
pagination and the same ``rsql_filter`` / ``limit`` / ``start`` /
|
|
596
|
+
``sort`` arguments as ``search_tickets``:
|
|
597
|
+
|
|
598
|
+
.. code-block:: python
|
|
599
|
+
|
|
600
|
+
from glpi_python_client import PatchComputer, PostComputer
|
|
601
|
+
|
|
602
|
+
computer_id = client.create_computer(
|
|
603
|
+
PostComputer(name="ws-1042", serial="PF3KL9QJ")
|
|
604
|
+
)
|
|
605
|
+
client.update_computer(
|
|
606
|
+
computer_id, PatchComputer(comment="Reimaged for the finance team")
|
|
607
|
+
)
|
|
608
|
+
computer = client.get_computer(computer_id)
|
|
609
|
+
print(computer.id, computer.name, computer.serial)
|
|
610
|
+
|
|
611
|
+
results = client.search_computers("name==ws-1042", limit=5)
|
|
612
|
+
for c in results:
|
|
613
|
+
print(c.id, c.name)
|
|
614
|
+
|
|
615
|
+
Example output::
|
|
616
|
+
|
|
617
|
+
1042 ws-1042 PF3KL9QJ
|
|
618
|
+
1042 ws-1042
|
|
619
|
+
|
|
620
|
+
Linking a computer to a contract
|
|
621
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
622
|
+
|
|
623
|
+
A computer's coverage contracts are tracked as links under
|
|
624
|
+
``/Assets/Computer/{id}/Contract``, exposed as
|
|
625
|
+
``list_computer_contracts``, ``get_computer_contract``,
|
|
626
|
+
``link_computer_contract``, ``update_computer_contract``, and
|
|
627
|
+
``unlink_computer_contract``:
|
|
628
|
+
|
|
629
|
+
.. code-block:: python
|
|
630
|
+
|
|
631
|
+
from glpi_python_client import IdNameRef, PostContract, PostContractItem
|
|
632
|
+
|
|
633
|
+
contract_id = client.create_contract(PostContract(name="Dell ProSupport 2026"))
|
|
634
|
+
|
|
635
|
+
link_id = client.link_computer_contract(
|
|
636
|
+
computer_id, PostContractItem(contract=IdNameRef(id=contract_id))
|
|
637
|
+
)
|
|
638
|
+
for link in client.list_computer_contracts(computer_id):
|
|
639
|
+
print(link.id, link.itemtype, link.items_id)
|
|
640
|
+
|
|
641
|
+
client.unlink_computer_contract(computer_id, link_id, force=True)
|
|
642
|
+
|
|
643
|
+
Example output::
|
|
644
|
+
|
|
645
|
+
17 Computer 1042
|
|
646
|
+
|
|
647
|
+
The underlying ``Contract_Item`` GLPI resource is shared by every asset
|
|
648
|
+
type, so ``PostContractItem`` and ``PatchContractItem`` both carry an
|
|
649
|
+
``itemtype`` field typed as a free string rather than an enum --
|
|
650
|
+
nothing stops a caller from writing ``"Computre"``. Because of that,
|
|
651
|
+
``link_computer_contract`` and ``update_computer_contract`` ignore
|
|
652
|
+
whatever ``itemtype`` and ``items_id`` are set on the body passed in
|
|
653
|
+
and set both fields themselves from ``computer_id``. Pass only
|
|
654
|
+
``contract`` (and ``comment``, if the contract ever adds one); a typo
|
|
655
|
+
in the two identifying fields would otherwise attach the link to the
|
|
656
|
+
wrong kind of object with no error from either side.
|
|
657
|
+
|
|
658
|
+
Contracts
|
|
659
|
+
~~~~~~~~~
|
|
660
|
+
|
|
661
|
+
The contract mixin maps to ``/Management/Contract`` with the usual
|
|
662
|
+
``search_ / get_ / create_ / update_ / delete_`` shape and
|
|
663
|
+
``iter_search_contracts`` for streaming pagination:
|
|
664
|
+
|
|
665
|
+
.. code-block:: python
|
|
666
|
+
|
|
667
|
+
from glpi_python_client import PatchContract, PostContract
|
|
668
|
+
|
|
669
|
+
contract_id = client.create_contract(
|
|
670
|
+
PostContract(name="Dell ProSupport 2026", number="CTR-2026-001")
|
|
671
|
+
)
|
|
672
|
+
client.update_contract(
|
|
673
|
+
contract_id, PatchContract(comment="Renewed for another year")
|
|
674
|
+
)
|
|
675
|
+
contract = client.get_contract(contract_id)
|
|
676
|
+
print(contract.id, contract.name, contract.date_begin)
|
|
677
|
+
|
|
678
|
+
results = client.search_contracts("name==Dell ProSupport 2026", limit=5)
|
|
679
|
+
for c in results:
|
|
680
|
+
print(c.id, c.name)
|
|
681
|
+
|
|
682
|
+
Example output::
|
|
683
|
+
|
|
684
|
+
501 Dell ProSupport 2026 2026-01-15
|
|
685
|
+
501 Dell ProSupport 2026
|
|
686
|
+
|
|
687
|
+
.. warning::
|
|
688
|
+
|
|
689
|
+
``date_begin`` on :class:`~glpi_python_client.GetContract` and
|
|
690
|
+
:class:`~glpi_python_client.PostContract` is a plain
|
|
691
|
+
:class:`datetime.date`, not a :class:`~datetime.datetime`. The GLPI
|
|
692
|
+
contract declares this field with ``format: date`` -- a contract has
|
|
693
|
+
no time-of-day for its start. That choice is load-bearing, not
|
|
694
|
+
cosmetic: the server-clock conversion in ``models/_base.py`` that
|
|
695
|
+
rewrites timestamps into the configured ``server_timezone`` only
|
|
696
|
+
touches values that are instances of :class:`datetime.datetime`, and
|
|
697
|
+
a plain :class:`~datetime.date` is not one, so ``date_begin`` never
|
|
698
|
+
enters that conversion. Had it been modelled as ``datetime`` it would
|
|
699
|
+
have been eligible, and converting a midnight, offset-naive value
|
|
700
|
+
between timezones can roll it onto the previous or next calendar
|
|
701
|
+
day. Note the asymmetry: ``date_begin`` and ``date_end`` on
|
|
702
|
+
``ContractCost`` (below) *are* ``datetime`` fields, because the
|
|
703
|
+
contract declares those two with ``format: date-time``. That
|
|
704
|
+
difference comes from the GLPI contract itself and is not an
|
|
705
|
+
inconsistency to reconcile.
|
|
706
|
+
|
|
707
|
+
Contract costs
|
|
708
|
+
^^^^^^^^^^^^^^
|
|
709
|
+
|
|
710
|
+
Cost lines live under ``/Management/Contract/{id}/Cost`` as a genuine
|
|
711
|
+
sub-resource with their own create, update, and delete endpoints:
|
|
712
|
+
``list_contract_costs``, ``get_contract_cost``,
|
|
713
|
+
``create_contract_cost``, ``update_contract_cost``, and
|
|
714
|
+
``delete_contract_cost``.
|
|
715
|
+
|
|
716
|
+
.. code-block:: python
|
|
717
|
+
|
|
718
|
+
from glpi_python_client import PatchContractCost, PostContractCost
|
|
719
|
+
|
|
720
|
+
cost_id = client.create_contract_cost(
|
|
721
|
+
contract_id, PostContractCost(name="Year 1", cost=4200.0)
|
|
722
|
+
)
|
|
723
|
+
client.update_contract_cost(
|
|
724
|
+
contract_id, cost_id, PatchContractCost(comment="Paid on invoice #88")
|
|
725
|
+
)
|
|
726
|
+
cost = client.get_contract_cost(contract_id, cost_id)
|
|
727
|
+
print(cost.id, cost.name, cost.cost)
|
|
728
|
+
|
|
729
|
+
print(len(client.list_contract_costs(contract_id)))
|
|
730
|
+
|
|
731
|
+
client.delete_contract_cost(contract_id, cost_id, force=True)
|
|
732
|
+
|
|
733
|
+
Example output::
|
|
734
|
+
|
|
735
|
+
9 Year 1 4200.0
|
|
736
|
+
1
|
|
737
|
+
|
|
738
|
+
.. note::
|
|
739
|
+
|
|
740
|
+
``costs`` on :class:`~glpi_python_client.GetContract` is read-only:
|
|
741
|
+
it comes back populated with references to the contract's cost
|
|
742
|
+
lines, but the field does not exist at all on ``PostContract`` or
|
|
743
|
+
``PatchContract``. Write cost lines through
|
|
744
|
+
``create_contract_cost``, ``update_contract_cost``, and
|
|
745
|
+
``delete_contract_cost`` instead of trying to assign ``costs`` on
|
|
746
|
+
the parent contract.
|
|
747
|
+
|
|
748
|
+
Contract types
|
|
749
|
+
^^^^^^^^^^^^^^
|
|
750
|
+
|
|
751
|
+
``/Dropdowns/ContractType`` is a plain dropdown: ``search_ / get_ /
|
|
752
|
+
create_ / update_ / delete_`` plus ``iter_search_contract_types``.
|
|
753
|
+
Unlike ``search_computers`` and ``search_contracts``, the contract-type
|
|
754
|
+
search helpers do not accept a ``sort`` argument.
|
|
755
|
+
|
|
756
|
+
.. code-block:: python
|
|
757
|
+
|
|
758
|
+
from glpi_python_client import PostContractType
|
|
759
|
+
|
|
760
|
+
type_id = client.create_contract_type(PostContractType(name="Maintenance"))
|
|
761
|
+
contract_type = client.get_contract_type(type_id)
|
|
762
|
+
print(contract_type.id, contract_type.name)
|
|
763
|
+
|
|
764
|
+
Example output::
|
|
765
|
+
|
|
766
|
+
6 Maintenance
|
|
767
|
+
|
|
768
|
+
Assign the type -- and a renewal behaviour -- through the parent
|
|
769
|
+
contract:
|
|
770
|
+
|
|
771
|
+
.. code-block:: python
|
|
772
|
+
|
|
773
|
+
from glpi_python_client import GlpiContractRenewalType, IdNameRef, PatchContract
|
|
774
|
+
|
|
775
|
+
client.update_contract(
|
|
776
|
+
contract_id,
|
|
777
|
+
PatchContract(
|
|
778
|
+
type=IdNameRef(id=type_id),
|
|
779
|
+
renewal_type=GlpiContractRenewalType.TACIT,
|
|
780
|
+
),
|
|
781
|
+
)
|
|
782
|
+
|
|
783
|
+
:class:`glpi_python_client.GlpiContractRenewalType` mirrors the three
|
|
784
|
+
values GLPI documents for ``Contract.renewal_type``: ``NONE`` (no
|
|
785
|
+
renewal), ``TACIT`` (automatic renewal), and ``EXPLICIT`` (manual
|
|
786
|
+
renewal).
|
|
787
|
+
|
|
583
788
|
Knowledge base
|
|
584
789
|
~~~~~~~~~~~~~~
|
|
585
790
|
|
|
@@ -685,8 +890,9 @@ the package root for easy use in RSQL filters:
|
|
|
685
890
|
:class:`glpi_python_client.GlpiTaskState`,
|
|
686
891
|
:class:`glpi_python_client.GlpiSolutionStatus`,
|
|
687
892
|
:class:`glpi_python_client.GlpiTimelinePosition`,
|
|
688
|
-
:class:`glpi_python_client.GlpiUserAuthType`,
|
|
689
|
-
:class:`glpi_python_client.GlpiGlobalValidation
|
|
893
|
+
:class:`glpi_python_client.GlpiUserAuthType`,
|
|
894
|
+
:class:`glpi_python_client.GlpiGlobalValidation`, and
|
|
895
|
+
:class:`glpi_python_client.GlpiContractRenewalType`.
|
|
690
896
|
|
|
691
897
|
.. code-block:: python
|
|
692
898
|
|
|
@@ -1552,6 +1758,36 @@ The whole page is built in one pass, so a single unconvertible record used
|
|
|
1552
1758
|
to make its page-mates unreadable too. The failure is now scoped to the
|
|
1553
1759
|
record whose body you actually read.
|
|
1554
1760
|
|
|
1761
|
+
The Markdown is CommonMark with GFM tables. Rendering it -- as the package
|
|
1762
|
+
does on the way back to GLPI, with cmark-gfm -- displays what GLPI
|
|
1763
|
+
displayed, and reading that rendering back gives the same Markdown. Text in
|
|
1764
|
+
a body is literal: Markdown has one spelling for ``__init__`` typed by a
|
|
1765
|
+
user and for bold ``init``, so text that would read as syntax is escaped:
|
|
1766
|
+
|
|
1767
|
+
.. code-block:: python
|
|
1768
|
+
|
|
1769
|
+
from glpi_python_client.content import GlpiContentConverter
|
|
1770
|
+
|
|
1771
|
+
GlpiContentConverter.from_transport(
|
|
1772
|
+
r"<p>Voir __init__ et \\serveur\compta</p><p># pas un titre</p>"
|
|
1773
|
+
)
|
|
1774
|
+
# Voir \_\_init\_\_ et \\\serveur\compta
|
|
1775
|
+
#
|
|
1776
|
+
# \# pas un titre
|
|
1777
|
+
|
|
1778
|
+
Ordinary prose stays as typed: ``fichier_de_test_v2.xlsx``, ``C:\Temp``,
|
|
1779
|
+
``R&D``, a ``#`` mid-sentence. The spelling is canonical: a line break reads
|
|
1780
|
+
back as ``\`` and a newline, a nested list is indented by its bullet's width,
|
|
1781
|
+
and a table comes back unpadded. A body with no HTML element is plain text
|
|
1782
|
+
and is read as GLPI shows it, its lines as lines.
|
|
1783
|
+
|
|
1784
|
+
Writing, your Markdown is rendered by cmark-gfm. A newline is a line break,
|
|
1785
|
+
GFM tables work, and raw HTML passes through, so put a placeholder such as
|
|
1786
|
+
``<login>`` in backticks. A write model keeps your Markdown verbatim unless
|
|
1787
|
+
it starts with an HTML tag, in which case it is read as HTML. A Markdown
|
|
1788
|
+
table needs a header row, so a header-less HTML table reads back with an
|
|
1789
|
+
empty one, and struck-through text stays as raw ``<s>``.
|
|
1790
|
+
|
|
1555
1791
|
.. note::
|
|
1556
1792
|
|
|
1557
1793
|
Deeply nested HTML is the case worth knowing about. The HTML-to-Markdown
|