Coverage for app/venv/lib/python3.14/site-packages/weblate/trans/management/commands/import_json.py: 0%
83 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 07:15 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 07:15 +0000
1# Copyright © Michal Čihař <michal@weblate.org>
2#
3# SPDX-License-Identifier: GPL-3.0-or-later
4from __future__ import annotations
6import json
7from pathlib import Path
8from typing import TYPE_CHECKING
10from django.core.exceptions import ValidationError
11from django.core.management.base import CommandError
12from django.utils.text import slugify
14from weblate.trans.models import Component, Project
15from weblate.utils.management.base import BaseCommand
17if TYPE_CHECKING:
18 from django.core.management.base import CommandParser
21class Command(BaseCommand):
22 """Command for mass importing of repositories into Weblate based on JSON data."""
24 help = "imports projects based on JSON data"
26 def add_arguments(self, parser: CommandParser) -> None:
27 super().add_arguments(parser)
28 parser.add_argument(
29 "--project", default=None, required=True, help="Project where to operate"
30 )
31 parser.add_argument(
32 "--ignore",
33 default=False,
34 action="store_true",
35 help="Ignore already existing entries",
36 )
37 parser.add_argument(
38 "--update",
39 default=False,
40 action="store_true",
41 help="Update already existing entries",
42 )
43 parser.add_argument(
44 "--main-component",
45 default=None,
46 help="Define which component will be used as main for the VCS repository",
47 )
48 parser.add_argument(
49 "json-file",
50 type=Path,
51 help="JSON file containing component definition",
52 )
54 def handle(self, *args, **options) -> None: # noqa: C901
55 """Automatic import of components."""
56 # Get project
57 try:
58 project = Project.objects.get(slug=options["project"])
59 except Project.DoesNotExist as error:
60 msg = "Project does not exist!"
61 raise CommandError(msg) from error
63 # Get main component
64 main_component = None
65 if options["main_component"]:
66 try:
67 main_component = Component.objects.get(
68 project=project, slug=options["main_component"]
69 )
70 except Component.DoesNotExist as error:
71 msg = "Main component does not exist!"
72 raise CommandError(msg) from error
73 try:
74 with options["json-file"].open("r") as handle:
75 try:
76 data = json.load(handle)
77 except json.JSONDecodeError as error:
78 msg = "Could not parse JSON file!"
79 raise CommandError(msg) from error
80 except OSError as error:
81 msg = f"Could not open file: {error}"
82 raise CommandError(msg) from error
84 allfields = {
85 field.name
86 for field in Component._meta.get_fields() # noqa: SLF001
87 if field.editable and not field.is_relation
88 }
90 # Handle dumps from API
91 if "results" in data:
92 data = data["results"]
94 for item in data:
95 if "filemask" not in item or "name" not in item:
96 msg = "Missing required fields in JSON!"
97 raise CommandError(msg)
99 if "slug" not in item:
100 item["slug"] = slugify(item["name"])
102 if "repo" not in item:
103 if main_component is None:
104 msg = "No main component and no repository URL!"
105 raise CommandError(msg)
106 item["repo"] = main_component.get_repo_link_url()
108 try:
109 component = Component.objects.get(slug=item["slug"], project=project)
110 except Component.DoesNotExist:
111 params = {key: item[key] for key in allfields if key in item}
112 component = Component(project=project, **params)
113 try:
114 component.full_clean()
115 except ValidationError as error:
116 for key, value in error.message_dict.items():
117 self.stderr.write(
118 "Error in {}: {}".format(key, ", ".join(value))
119 )
120 msg = "Component failed validation!"
121 raise CommandError(msg) from error
122 component.save(force_insert=True)
123 self.stdout.write(
124 f"Imported {component} with {component.translation_set.count()} translations"
125 )
126 else:
127 self.stderr.write(f"Component {component} already exists")
128 if options["ignore"]:
129 continue
130 if options["update"]:
131 for key in item:
132 if key not in allfields or key == "slug":
133 continue
134 setattr(component, key, item[key])
135 component.save()
136 continue
137 msg = "Component already exists, use --ignore or --update!"
138 raise CommandError(msg)