Package: le-utils
LE UtilsThele-utilspackage contains shared constants used by Ricecooker, Kolibri, and
Kolibri Studio. This package is not meant to be installed or used directly, but
plays an important role in all Learning Equality products.ConstantsThe Python files in thele_utils/constants/are used to
define constants (usually inALL_CAPSform) to be used from Python code.
The same constants and naming conventions are also provided in JSON format in the
folderle_utils/resources/for use in frontend code.
This means, adding a new constant may require editing multiple files: the Python
constant-defining file, the JSON-file, and any associated tests.LanguagesThe filele_utils/constants/languages.pyand
the lookup table inle_utils/resources/languagelookup.jsondefine the internal representation for languages codes used by Ricecooker, Kolibri,
and Kolibri Studio to identify educational content in different languages.The internal representation uses a mixture of two-letter codes (e.g.en),
two-letter-and-country code (e.g.pt-BRfor Brazilian Portuguese),
and three-letter codes (e.g.,zulfor Zulu).In order to make sure you have the correct language code when interfacing with
the Kolibri ecosystem (e.g. when uploading new content to Kolibri Studio), you
must lookup the language object using the helper methodgetlang:>>> from le_utils.constants.languages import getlang
>>> language_obj = getlang('en')       # lookup language using language code
>>> language_obj
Language(native_name='English', primary_code='en', subcode=None, name='English', ka_name=None)The functiongetlangwill returnNoneif the lookup fails. In such cases, you
can try lookup by name or lookup by alpha2 code (ISO_639-1) methods defined below.Once you've successfully looked up the language object, you can obtain the internal
representation language code from the language object'scodeattribute:>>> language_obj.code
'en'The Ricecooker API expects these internal representation language codes will be
supplied for alllanguageattributes (channel language, node language, and files language).More lookup helper methodsThe helper methodgetlang_by_nameallows you to lookup a language by name:>>> from le_utils.constants.languages import getlang_by_name
>>> language_obj = getlang_by_name('English')  # lookup language by name
>>> language_obj
Language(native_name='English', primary_code='en', subcode=None, name='English', ka_name=None)The modulele_utils.constants.languagesdefines two other language lookup methods:Usegetlang_by_native_namefor lookup up names by native language name,
e.g., you look for 'Français' to find French.Usegetlang_by_alpha2to perform lookups using the standard two-letter codes
defined inISO_639-1that are
supported by thepycountrieslibrary.Useful linksThe following websites are useful for researching language codes:https://www.ethnologue.com/https://en.wikipedia.org/wiki/List_of_ISO_639-2_codesLicensesAll content nodes within Kolibri and Kolibri Studio must have a license. The filele_utils/constants/licenses.pycontains the
constants used to identify the license types. These constants are meant to be
used in conjunction with the helper methodricecooker.classes.licenses.get_licenseto createLicenceobjects.To initialize a license object, you must specify the license type and thecopyright_holder(str) which identifies a person or an organization. For example:from ricecooker.classes.licenses import get_license
from le_utils.constants import licenses
license = get_license(licenses.CC_BY, copyright_holder="Khan Academy")Note: Thecopyright_holderfield is required for all License types except for
the public domain license for whichcopyright_holdercan be None.Content kinds (ContentNode subclasses)Content items throughout the Kolibri ecosystem come in several kinds. Thekindattribute of each object can be one of ("topic", "video", "audio", "exercise"
"document", or "html5".
Seeconstants/content_kinds.pyfor latest list.The currently supported content kinds are:Topic node (folder)Video content nodes backed by a video files and subtitlesAudio content nodes backed by an audio filesDocument content nodes backed by a document files (PDF or ePub)HTML5 app content nodes backed by a HTML5 zip filesSlideshow content nodesExercise content nodesThekindattribute identifies a subclass of the base content node class within
the data model, which differs on Ricecooker, Studio, and Kolibri:ricecooker.classes.nodes.ContentNode:
in-memory content node used to store metadata needed to upload new content to Kolibri  Studiocontentcuration.contentcuration.models.ContentNode:
node within one of the trees associated with a Kolibri Studio channel.kolibri.core.content.models.ContentNode:
node within tree for a particular version of a channel on Kolibri.For a detailed description of the common and different model attributes available
on content nodes in each part of the platform seethis doc.File formats (extensions)These are low-level constant that represents what type of file and are essentially
synonymous with file extensions. The file formatMP4is simply a convenient
proxy for the file extensionmp4.
Seefile_formats.pyandresourcces/formatlookup.json.Format presets (ContentNode-File relation)EveryContentNodeis associated with one or moreFileobjects and nature of
this association is represented though theformat_presetattribute of the file.
Theformat_presetis the role the file is playing in the content node,
e.g., thumbnail, high resolution video, or low resolution video.
Note that format presets are represented redundantly as python string inconstants/format_presets.pyand as jsonresources/presetlookup.json.You can think of the different format presets on a content node as different "slots"
to be filled in by files, with certain slots being required while other optional.
For examples, for a VideoNode (kind=video) to be a valid content node, it must
have at least one video file associated with it filling either thehigh_res_videoslot or thelow_res_videoslot. Certain slots can have multiple files in them,
like thevideo_subtitlepreset, since a VideoNode can have multiple subtitles
associated with it for different languages.The figure below illustrates the structure between content nodes, files, and format presets.In the Sample shown, the Video Node is of content kindvideoand has three
files associated with it:The first file has file formatmp4and format presethigh_res_videoThe second file is also inmp4format but the relation to the content node
is thatlow_res_videoA third file with formatvttis associated with the content node with a
format preset ofvideo_subtitle.Format presets play a crucial role throughout the Kolibri content ecosystem and
govern such things as content validation rules applied by Ricecooker, Kolibri Studio
edit rules, and the rendering logic on Kolibri.File types (ricecooker.files.File subclasses)Used on Ricecooker as identifiers to represents what type of file when serializing
things to JSON as part of the content import process. Note that file types constants
are internal to ricecooker operations and are not used in Kolibri Studio or Kolibri.ExercisesThe filele_utils/constants/exercises.pycontains identifiers for different question types and mastery models.Proquint Channel TokensThe filele_utils/proquint.pycontains helper methods
for generating proquint identifiers for content channels. These are short strings
that are easy to enter on devices without a full keyboard, e.g.sutul-hakuh.RolesTheroleconstants are used for Role-based access control (RBAC) within the
Kolibri platform. Currently, only two levels of visibility are supported:learner(default): content nodes are visible to all Kolibri userscoach: content nodes are only visible to Kolibri coaches and administratorsMetadata labelsThese are encoded in spec/labels-v*.json. Once a spec has been finalized it will be
added to finalized_specs.yml to ensure that CI will fail any future modifications
to this specification. This ensures that the resulting built code has consistent
ordering so that generated bits for bitmasks are stable across releases.
We also require that all names in the specs be globally unique to minimize confusion
and reduce the chance of collisions in translations of these terms for users.