package names

package names

Returns a list of the names of all packages in the interpreter for which a version has been provided (via package provide) or for which a package ifneeded script is available. The order of elements in the list is arbitrary.


package names will only deliver all available packages if it has searched all package indices before. To force this, do a dummy package require before:

catch {package require nonexistentName}
package names

DGP - To be more precise, [package names] returns a list of all the package names that are already known to the [package] command. That is not the same as all the names that could become known by operation of the [package unknown] callback.

The default [package unknown] callback is [tclPkgUnknown] and it is that default callback that exhibits the behavior described above -- after one run, all installed package names are known. The [package unknown] interface does not require that behavior, and other callbacks may not (IMHO, should not) implement it.

Lars H: Feeling slightly Cantorian, I'd propose the following for a foolproof (never loading a package, even if it's got a bizarre name) method of listing all package names:

proc all_package_names {} {
  set res ""
  while {$res ne [set res [package names]]} {
     if {[package unknown] eq ""} then {break}
     uplevel #0 [package unknown] [list $res+1 ""]
  }
  return $res
}

The idea is that "[package names]+1" cannot be the name of a package known to the package database, so telling package unknown to search for it will force some additional data to be entered (even with a very lazy package unknown handler) as long as there is any.

LV: Can someone help me understand the above code? The uplevel would, it would seem, attempt to run the subsequent command in the caller's context. The command that is being run is the current package's unknown script is being executed, with arguments of all the currently known packages, and the last one having a +1 appended to its name followed by an empty string. I don't understand what that is trying to do.

Lars H: The uplevel is supposed to do exactly what package require would when encountering a package name for which no ifneeded script is known yet. However, we need to pass it a name of the package to look for, so we use the string representation of the list of known package names to generate one which is not in there. As for the the +1, well, I did warn I was feeling Cantorian [L1 ] when I wrote that…

TR: The above code can be supplemented (following a code suggestion on TkChat from sbron) to list all packages with their versions and source info:

proc all_package_names {} {
   set res ""
   while {$res ne [set res [package names]]} {
      if {[package unknown] eq ""} then {break}
      uplevel #0 [package unknown] [list $res+1 ""]
   }
   foreach pkg $res {
      foreach ver [package versions $pkg] {
         puts "$pkg ($ver): [package ifneeded $pkg $ver]"
      }
   }
}

LV 2008 Jun 05 Did something change with the way package names, etc. worked in Tcl 8.5? The reason I ask is this. Under Tcl 8.4, when I ran this routine, I would get over 400 names returning in ActiveTcl. Under ActiveTcl 8.5, I am only seeing 100. Now, I know that ActiveTcl, out of the box, comes with fewer packages. But what I am seeing is different. For instance, most of the tcllib packages are displaying differently now. I have tcllib installed in both local teapots. I can start up both tclsh's , do a package require math::bigfloat and get it.

However, the above code, when run against tcl 8.4.19, shows all the math::bigfloat, etc. routines, but when run against activetcl 8.5.2, the routine only shows math, with none of the ::other names. They are there in AT 8.5 - just not showing up. Even at the top level - things like md5 shows when I run the above code in AT 8.4 but not AT 8.5.

It seems as if somehow things are just not quite the same.

Lars H: There have certainly been changes — Tcl Modules and TIP#268 [L2 ] are two that come to mind — but it's not obvious that any of them should cause this. Perhaps something has changed in the package unknown callback? (Well, modules certainly require changes there.) Maybe this is even something special to ActiveTcl? I believe the exact command used for package unknown callback is something distributions are allowed to fiddle around with. On TclTkAqua I get 412 packages in 8.5 and 410 packages in 8.4.

LV In June, 2008, in comp.lang.tcl (thread titled "the purpose of tcllib") [L3 ], Don Porter points out that Tcl Modules, which are also items that package require can load, do not current appear in the output of package names. Also, another point is made that there is always the possibility that packages lie in non-standard paths or have names that are dynamically created, so getting a full list of the packages available is not possible.

That tcl module limitation, though, is the tough one, since more and more packages are likely to use that...

NEM To clarify, I believe Tcl Modules with simple names (i.e. no :: in them) and which are directly in one of the dirs on the tcl::tm::path list should show up after a package unknown call. It is modules in sub-directories called something like math::calculus that will not show up immediately. I'm not sure if this is what is causing the difference between AT 8.4 and 8.5, or if it is some other change to the package unknown handler. It is a shame though. I wish I'd paid more attention to those TIPs.


APN Another change I noticed is that with Tcl 8.5 modules, package names cannot have "-" in them. Thus app-wits-2.0.tm is not found by package require but appwits-2.0.tm is. I guess the pattern matching treats "-" as start of the version string.

Lars H: Yes, by definition [L4 ] only alphanumeric characters, underscore and colons are allowed in the package names of modules, due to restrictions in names of .tm files eligible as modules. I guess you'll have to go for app_wits as package name if you consider the word separator to be important.


See also: