Skip to content

REF002: unknown-library-member

Library module or function does not exist

Code REF002
Name unknown-library-member
Category References (REF)
Default severity error
Enabled by default yes
Fix available no
ign-lint equivalent none

Resolves every use of the project script library in scripts against the library the project sees (its own modules and inherited ones): attribute chains such as core.util.fmt(...), chains through aliases (u = core.util, from core.util import fmt) and import statements. Paths through another library module's import continue in the module the import leads to: m0.util.nope is checked in lib.util when m0 does from lib import util or import lib.util as util, and so is m0.lib.util.nope when m0 does import lib.util (which binds lib), at any depth (measured with Ignition's ScriptManager on 8.3.3). It reports:

  • a package without the module (core.nope where core/ has no nope);
  • a module without the attribute (core.util.nope where core/util/code.py defines no top-level nope);
  • a child module hidden by its parent's own code.py: a folder with a code.py is a module, and Ignition cannot reach the modules below it (see SCR304).

A module's top-level names are those its module-level code binds, including names bound through global in functions, names it imports, and the globals every script sees (system, fpmi, sys and the library's top-level packages).

The rule stays silent where it cannot be sure: modules whose namespace is dynamic (from x import *, exec, writes through globals(), code that reads or writes a frame's or a module's names by itself such as sys._getframe(), .f_globals or e = eval; reflection that is only a first hop, such as a .type Java member or getattr with a computed name, does not count, see docs/internal/fix-safety.md, "Frame routes: findings and fixes"), modules that do not parse, paths through a name the module binds otherwise too (try: from lib import util / except: util = None), through a star import or around a cycle of imports, uses inside a try that catches AttributeError, ImportError, NameError or Exception, dunder attributes, the members of Ignition's library module and package objects that the module does not bind (core.util.dict, core.util.getName(), core.clear(); see docs/internal/fix-safety.md, "Library module objects"), scripts of projects whose parent project is not in the workspace, and names that a project inheriting from the script's project defines, and names a resource of the project stores, through any path (core.util.flag = True counts for m0.util.flag when m0 imports core.util as util, and m0.util.flag = True for core.util.flag; a delete or augmented assignment creates nothing). Plain attribute stores themselves are not checked; deleting a missing name (del core.util.flag, a KeyError on 8.3.3, unless a try catches it) and changing one with an augmented assignment (core.util.flag += 1, an AttributeError) are reported.

A use behind a check that the name exists (if hasattr(core.util, "flag"):) is reported all the same when no code anywhere creates the name, whether it reads, deletes or augments it: the check only hides the missing name, and the code it guards never runs. Once a script of the project creates the name (core.util.flag = True), none of them is reported.

The script raises AttributeError (or ImportError) when it reaches the name. A missing library name is almost always a renamed or moved function or module.

core.util.formatUnits(value)

Use instead (the function is called formatUnit):

core.util.formatUnit(value)

Generated from the rule metadata by iglint generate-docs; iglint rule REF002 prints the same page in the terminal. Source: docs/rules/REF002.md.