def print_demand()

in src/hpc/autoscale/job/demandprinter.py [0:0]


    def print_demand(self, demand_result: DemandResult) -> None:
        rows = []
        columns = self.column_names
        if not columns:
            columns = self._get_all_columns(demand_result.compute_nodes)

        if self.output_format == "json":
            columns = [c for c in columns if c not in ["hostname_required"]]
        else:
            columns = [
                c
                for c in columns
                if c not in ["available", "node", "hostname_required"]
            ]

        columns = ["job_ids" if c == "assigned_job_ids" else c for c in columns]
        if "name" in columns:
            columns.remove("name")
            columns.insert(0, "name")

        short_columns = [c.split("@")[0] for c in columns]
        long_columns = [c.split("@")[-1] for c in columns]

        # sort by private ip or the node name

        def sort_by_ip_or_name(node: Node) -> Any:
            if node.private_ip:
                return tuple(map(int, node.private_ip.split(".")))

            name_toks = node.name.split("-")
            if name_toks[-1].isdigit():
                node_index = int(name_toks[-1])
                nodearray_ord = [ord(x) for x in node.nodearray]
                # 2**31 to make these come after private ips
                # then nodearray name, then index
                return tuple([2**31] + nodearray_ord + [node_index])
            return tuple([-1] + name_toks)

        ordered_nodes = sorted(demand_result.compute_nodes, key=sort_by_ip_or_name)

        for node in ordered_nodes:
            row: List[str] = []
            rows.append(row)
            for column in long_columns:
                # TODO justify - this is a printing function, so this value could be lots of things etc.

                value: Any = None
                is_from_available = column.startswith("*")
                is_ratio = column.startswith("/")
                is_slice = "[" in column

                if is_from_available or is_ratio:
                    column = column[1:]

                def _slice(v: str) -> str:
                    return v

                slice = _slice

                if is_slice:
                    slice_expr = column[column.index("[") :]
                    column = column.split("[")[0]
                    # TODO maybe parse this instead of eval-ing a lambda
                    if self.long:
                        slice = lambda v: v  # noqa: E731
                    else:
                        slice = eval(
                            "lambda v: v%s if v is not None else v" % slice_expr
                        )

                if column == "hostname":
                    hostname = node.hostname

                    if not node.exists or not hostname:
                        if node.private_ip:
                            hostname = Hostname(str(node.private_ip))
                        else:
                            hostname = Hostname("tbd")
                    value = hostname
                elif column == "hostname_required":
                    continue
                elif column == "job_ids":
                    value = node.assignments
                elif hasattr(node, column):
                    value = getattr(node, column)
                else:
                    if is_from_available:
                        value = node.available.get(column)
                    elif is_ratio:
                        value = "{}/{}".format(
                            node.available.get(column), node.resources.get(column)
                        )
                    elif column in node.resources:
                        value = node.resources.get(column)
                    else:
                        value = node.metadata.get(column)
                    
                    if value is None:
                        buckets = demand_result.buckets_by_id.get(node.bucket_id, [])
                        if buckets:
                            bucket = buckets[0]
                            if hasattr(bucket, column):
                                value = getattr(bucket, column)

                if value is None:
                    value = self.__defaults.get(column)

                # convert sets to lists, as sets are not json serializable
                if isinstance(value, set):
                    value = list(value)
                elif isinstance(value, datetime):
                    value = value.isoformat()

                # for json, we support lists, null, numbers etc.
                # for table* we will output a string for every value.
                if self.output_format != "json":
                    if isinstance(value, list):
                        value = ",".join(sorted(value))
                    elif isinstance(value, set):
                        value = ",".join(sorted(list(value)))
                    elif value is None:
                        value = ""
                    elif isinstance(value, float):
                        value = "{:.1f}".format(value)
                    elif not isinstance(value, str):
                        value = str(value)

                else:
                    if hasattr(value, "to_json"):
                        value = value.to_json()
                    elif hasattr(value, "keys"):
                        value = dict(value)

                row.append(slice(value))

        # remove / and slice expressions

        stripped_short_names = [c.lstrip("/").split("[")[0] for c in short_columns]
        if self.output_format != "json":
            stripped_short_names = [x.upper() for x in stripped_short_names]
        print_rows(stripped_short_names, rows, self.stream, self.output_format)