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 |
What it does
Section titled “What it does”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.nopewherecore/has nonope); - a module without the attribute (
core.util.nopewherecore/util/code.pydefines no top-levelnope); - a child module hidden by its parent's own
code.py: a folder with acode.pyis a module, and Ignition cannot reach the modules below it (seeSCR304).
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.
Why is this bad?
Section titled “Why is this bad?”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.
Example
Section titled “Example”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.