Coverage for portality / lcc.py: 58%
98 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-05 00:09 +0100
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-05 00:09 +0100
1"""
2~~LCC:Data->LCCXML:Data~~
3"""
4from portality.lib import paths
5from portality.models import LCC
6from portality.core import prepare_type
9def loadLCC(source=None):
10 # use delayed imports, as this code will only rarely be run
11 import os
12 from lxml import etree
14 if source is None:
15 source = paths.rel2abs(__file__, "..", "lccSubjects.xml")
17 doc = etree.parse(open(source))
18 root = doc.getroot()
20 nodes = {}
21 tree = {"name": "LCC", "children": []}
22 cpmap = {}
24 for element in root.findall("subject"):
25 nel = element.find("name")
26 cel = element.find("code")
27 pel = element.find("parent")
29 if nel is None:
30 continue
32 name = nel.text
33 code = None
34 parent = None
35 if cel is not None:
36 code = cel.text
37 if pel is not None:
38 parent = pel.text
40 node = {"name": name}
41 if code is not None:
42 node["code"] = code
44 nodes[name] = node
46 if parent is None:
47 tree["children"].append(node)
48 else:
49 cpmap[name] = parent
51 for child, parent in cpmap.items():
52 cn = nodes.get(child)
53 pn = nodes.get(parent)
54 if cn is None or pn is None:
55 continue
56 if "children" not in pn:
57 pn["children"] = []
58 pn["children"].append(cn)
60 lcc = LCC(**tree)
62 # Initialise the LCC index correctly if it doesn't exist - otherwise it'll be created badly on save
63 prepare_type(lcc.__type__)
64 lcc.save()
67def lcc2choices(thelcc, level=-2):
68 level += 1
69 level_indicator = '--'
70 if 'children' in thelcc:
71 results = []
72 if thelcc['name'] != 'LCC':
73 # don't want the root + it doesn't have a code
74 results += [(thelcc['code'], level_indicator * level + thelcc['name'])]
75 for child in thelcc['children']:
76 results += lcc2choices(child, level=level)
77 return results
78 else:
79 # this is a leaf
80 if 'code' not in thelcc:
81 if thelcc['name'] == 'TMP':
82 # some weird leaf element at 1st level of the tree
83 # don't want to generate a choice for it, just ignore
84 return []
85 return [(thelcc['code'], level_indicator * level + thelcc['name'])]
88def lcc2jstree(thelcc):
89 if 'children' in thelcc:
90 results = []
91 if thelcc['name'] == 'LCC':
92 for child in thelcc['children']:
93 results += lcc2jstree(child)
94 else:
95 # don't want the root + it doesn't have a code
96 newnode = {
97 "id": thelcc['code'],
98 "text": thelcc['name'],
99 "children": []
100 }
101 for child in thelcc['children']:
102 newnode['children'] += lcc2jstree(child)
103 results.append(newnode)
105 return results
106 else:
107 # this is a leaf
108 if 'code' not in thelcc:
109 if thelcc['name'] == 'TMP':
110 # some weird leaf element at 1st level of the tree
111 # don't want to generate a choice for it, just ignore
112 return []
113 return [
114 {
115 "id": thelcc['code'],
116 "text": thelcc['name'],
117 "children": []
118 }
119 ]
122def lcc2flat_code_index(thelcc):
123 if 'children' in thelcc:
124 results = {}
125 if thelcc['name'] != 'LCC':
126 # don't want the root + it doesn't have a code
127 results.update({thelcc['code']: thelcc['name']})
128 for child in thelcc['children']:
129 results.update(lcc2flat_code_index(child))
130 return results
131 else:
132 # this is a leaf
133 if 'code' not in thelcc:
134 if thelcc['name'] == 'TMP':
135 # some weird leaf element at 1st level of the tree
136 # don't want to generate a choice for it, just ignore
137 return {}
138 return {thelcc['code']: thelcc['name']}
141lcc = LCC.pull('lcc')
142if not lcc:
143 loadLCC()
144lcc = LCC.pull('lcc')
145lcc_choices = []
146lcc_jstree = []
147lcc_index_by_code = {}
148if lcc:
149 lcc_choices = lcc2choices(lcc)
150 lcc_jstree = lcc2jstree(lcc)
151 lcc_index_by_code = lcc2flat_code_index(lcc)
154def lookup_code(code):
155 return lcc_index_by_code.get(code)