def slurp_role(element_name, attributes): """Look at a specific <role>-element""" if element_name != "rolle": return # what *kind* of role is this? role_kind = attributes[role_parser.target_key] if len(role_kind) != 1: # A warning about this has has already been issued return role_kind = role_kind[0] if role_kind not in fs_handler.valid_roles: logger.debug("Ignoring '%s' role for: %s", role_kind, repr(attributes)) return if not timeslot_is_valid(lower(attributes)): logger.debug("Ignoring '%s' - data too old/in the future: " "attrs=%s", role_kind, lower(attributes)) return attrs = fs_handler.fixup_attributes(attributes) if attrs["rollekode"] not in fs_handler.valid_role_codes: logger.debug("Ignoring '%s' role, role code %s: attrs=%s", role_kind, attrs["rollekode"], attrs) return logger.debug("Collecting role '%s' with %s", role_kind, repr(attributes)) group_key = fs_handler.attributes2key(role_kind, attrs) if group_key is None: return fs_handler.register_description(group_key, attrs) if group_key is None: logger.warn("Failed to create group key for role=%s/attrs=%s", role_kind, attrs) return if not fs_handler.role_is_exportable(role_kind, attrs): logger.debug("Ignoring role=%s/attrs=%s (not exportable to LMS)", role_kind, attrs) return fnr = "%06d%05d" % (int(attrs["fodselsdato"]), int(attrs["personnr"])) result.setdefault(group_key, set()).add(fnr)
def attributes2key(self, group_kind, attributes): """Construct a Cerebrum group_name/CF group id, given a bunch of attributes. This function is useful to map various information tidbits on groups, roles, etc to a unique ID in Cerebrum for that particular kind of attributes. Each L{group_kind} results in a group in Cerebrum and this function calculates that group's id (not entity_id, but the id used in CF). @type group_kind: basestring @param group_kind: A tag that describes what kind of information is to be expected in L{attributes}. The ONLY legal values are: - 'stprog', 'kull', 'kullklasse', 'undenh', 'undakt' - 'student-undenh', 'student-undakt', 'student-kullklasse', 'student-kull' Each kind has a different set of keys in attributes that MUST be present. @type attributes: dict (of basestring -> basestring) @param attributes: A collection of attributes. This collection may contain more than what is required by L{group_kind}. @rtype: basestring or None @return: None if an id could not be constructed. The id itself otherwise. """ # easiest way to copy, since we modify these destructively attrs = lower(attributes) if group_kind not in self.group_kind2required_keys: logger.warn("Don't know how to process attributes " "belonging to '%s' (%s)", group_kind, repr(attrs)) return None keys = self.group_kind2required_keys[group_kind] if not all(x in attrs for x in keys): logger.warn("Missing essential keys for kind=%s. " "Required=%s, available=%s", group_kind, sorted(keys), sorted(attrs)) return None # Now, those that have "terminnr" > 1 MUST be remapped. if "terminnr" in keys: attrs = count_back_semesters(attrs) result_id = self.group_kind2name_template[group_kind] result_id = result_id % attrs return result_id
def fixup_attributes(self, attributes): """Convert attributes to standard form and amend with extra keys. This is a convenience/external method. """ # Force lowercase, so we won't have to bother about this later. attrs = lower(attributes) # Force-insert a few required attributes attrs = self._extend_attributes(attrs) return attrs
def _stprog2avdeling(self, stprog_file): """Create a dictionary mapping stprog to avdeling (department). fs.studieprogram.faknr_studieansv is the value we want. """ result = dict() for entry in EduDataGetter(stprog_file, logger).iter_stprog(): attrs = lower(entry) stprog = attrs["studieprogramkode"] result[stprog] = "%02d0000" % int(attrs["faknr_studieansv"]) logger.debug("Collected %d stprog->avdeling mappings from %s", len(result), stprog_file) return result
def _load_emne_names(self, undenh_file): """Slurp in the human-friendly names from undenh_file. """ result = dict() for entry in EduDataGetter(undenh_file, logger).iter_undenh("undenhet"): if "emnenavn_bokmal" in entry: name = entry["emnenavn_bokmal"] elif "emnenavnfork" in entry: name = entry["emnenavnfork"] else: name = "" result[lower(entry["emnekode"])] = name return result
def _load_exportable_keys(self, stprog_file, undenh_file, undakt_file): """Build a set of FS 'entity' keys that are exportable to LMS. There is a constraint placed by hiof on stprog, undenh and undakt. If status_eksport_lms = 'J', then the entity in question is exportable to CF. If it is NOT, then it should be interpreted as if the entity did not exist. This means that any group related to, say, a non-exportable stprog is skipped as well (*ALL* kull/kullklasse/roles associated with that stprog). @param stprog_file: See L{__init__}. @param undenh_file: See L{__init__}. @param undakt_file: See L{__init_-} @rtype: set (of str) @return: A dict containing the keys for all exportable stprog/undenh/undakt and the corresponding names. The latter is useful for group naming. """ result = set() for (source, entry_kind) in ((EduDataGetter(stprog_file, logger).iter_stprog, "stprog",), (lambda: EduDataGetter(undenh_file, logger).iter_undenh("undenhet"), "undenh",), (EduDataGetter(undakt_file, logger).iter_undakt, "undakt",)): logger.debug("Loading exportable %s", entry_kind) for entry in source(): attrs = lower(entry) key = self._attributes2exportable_key(entry_kind, attrs) if attrs["status_eksport_lms"] == 'j': result.add(key) logger.debug("%s=%s is%sexportable", entry_kind, key, key in result and " " or " not ") return result
def _load_exportable_keys(self, stprog_file, undenh_file, undakt_file): """Build a set of FS 'entity' keys that are exportable to LMS. There is a constraint placed by hiof on stprog, undenh and undakt. If status_eksport_lms = 'J', then the entity in question is exportable to CF. If it is NOT, then it should be interpreted as if the entity did not exist. This means that any group related to, say, a non-exportable stprog is skipped as well (*ALL* kull/kullklasse/roles associated with that stprog). @param stprog_file: See L{__init__}. @param undenh_file: See L{__init__}. @param undakt_file: See L{__init_-} @rtype: set (of str) @return: A dict containing the keys for all exportable stprog/undenh/undakt and the corresponding names. The latter is useful for group naming. """ result = set() for (source, entry_kind) in ((EduDataGetter(stprog_file, logger).iter_stprog, "stprog",), (lambda : EduDataGetter(undenh_file, logger).iter_undenh("undenhet"), "undenh",), (EduDataGetter(undakt_file, logger).iter_undakt, "undakt",)): logger.debug("Loading exportable %s", entry_kind) for entry in source(): attrs = lower(entry) key = self._attributes2exportable_key(entry_kind, attrs) if attrs["status_eksport_lms"] == 'j': result.add(key) logger.debug("%s=%s is%sexportable", entry_kind, key, key in result and " " or " not ") return result
def _attributes2exportable_key(self, attr_kind, attributes): """A help method to create an internal lookup key. This is for internal usage only. The key is similar to group.group_name for the groups we create (but not quite the same). @type attr_kind: basestring @param attr_kind: String tagging the attributes. @type attributes: dict (basestring -> basestring) @param attributes: Attributes from which a key is derived @rtype: basestring @return: Key calculated from L{attributes}. """ key = None attrs = lower(attributes) if attr_kind == "undenh": attrs = count_back_semesters(attrs) key = ":".join((attrs[x] for x in ("arstall", "terminkode", "emnekode", "versjonskode", "terminnr"))) elif attr_kind == "undakt": attrs = count_back_semesters(attrs) key = ":".join((attrs[x] for x in ("arstall", "terminkode", "emnekode", "versjonskode", "terminnr", "aktivitetkode"))) elif attr_kind in ("stprog", "kull", "kullklasse"): key = attributes["studieprogramkode"] else: assert False, "NOTREACHED" return key
def slurp_emne(element, attributes): if element == "emne": emne = lower(attributes["emnekode"]) result[emne] = "%02d0000" % int(attributes["faknr_reglement"])