Skip to main content

objectcrawler

Basic and lightweight python tool for inspecting python objects.

Originally built for objects defining __slots__, however it also handles the __dict__ attribute just fine.

Installation

  1. Create a fork of this repo
  2. Clone the forked repo to your machine
  3. Install with pip install ObjectCrawler

For development you can install using the pip -e editable flag.

Feel free to file a pull request if you make any changes!

Usage

Inspecting an object is simple, import the Crawler class and feed it the object in question:

from objectcrawler import Crawler
print(Crawler(...))

Demo

Lets demonstrate this with a simple class:

class Food:
    __slots__ = ["name"]
    def __init__(self, name: str):
        self.name = name

    def __repr__(self):
        return f"Food({self.name})"

After creating an instance of this class, we can inspect it:

from objectcrawler import Crawler
a = Food("Apple")
print(Crawler(a))

This will output the following table:

────────────┬──────────────┬────────────┬─────────
assignment  │ value        │ classname  │ source
────────────┼──────────────┼────────────┼─────────
~           │ Food(Apple)  │ Food       │ self
└─ name     │ Apple        │ str        │ Food

Inheritance

The purpose of the source column is to display information about inheritance.

If we create a subclass, we can see this behaviour:

class PreparedFood(Food):
    __slots__ = ["prep_time"]
    def __init__(self, name: str, prep_time: int):
        super().__init__(name)

        self.prep_time = prep_time

    def __repr__(self):
        return f"PreparedFood({self.name}, {self.prep_time})"

b = PreparedFood("Pasta", 10)
print(Crawler(b))

Giving the following table. Note the source column:

──────────────┬──────────────────────────┬───────────────┬───────────────
assignment    │ value                    │ classname     │ source
──────────────┼──────────────────────────┼───────────────┼───────────────
~             │ PreparedFood(Pasta, 10)  │ PreparedFood  │ None
├─ prep_time  │ 10                       │ int           │ PreparedFood
└─ name       │ Pasta                    │ str           │ Food

Iterators

Iterators are a special case, since they are implicit storage containers, an attempt is made to "unpack" them into the data tree.

lists, tuples, etc. wil have their assignment set to the index

dicts, OrderedDicts, etc. will have their assignment set to the key (the object must provide a iter() method for this functionality)

class Meal:
    __slots__ = ["name", "ingredients"]
    def __init__(self, name: str, ingredients: list):
        self.name = name
        self.ingredients = ingredients

ingredients = [
    Food("Cheese"),
    PreparedFood("Beans", 10),
    PreparedFood("Toast", 5)
]

c = Meal("Cheesy Beans on Toast", ingredients)
print(Crawler(c))
────────────────────┬───────────────────────────────────────────┬───────────────┬───────────────
assignment          │ value                                     │ classname     │ source
────────────────────┼───────────────────────────────────────────┼───────────────┼───────────────
~                   │ <__main__.Meal object at 0x762f4d65de10>  │ Meal          │ None
├─ name             │ Cheesy Beans on Toast                     │ str           │ Meal
└─ ingredients      │ iterable: list                            │ list          │ Meal
│  ├─ 0             │ Food(Cheese)                              │ Food          │ Meal
│  │  └─ name       │ Cheese                                    │ str           │ Food
│  ├─ 1             │ PreparedFood(Beans, 10)                   │ PreparedFood  │ Meal
│  │  ├─ prep_time  │ 10                                        │ int           │ PreparedFood
│  │  └─ name       │ Beans                                     │ str           │ Food
│  └─ 2             │ PreparedFood(Toast, 5)                    │ PreparedFood  │ Meal
│  │  ├─ prep_time  │ 5                                         │ int           │ PreparedFood
│  │  └─ name       │ Toast                                     │ str           │ Food

Differences

If you're trying to debug a class and have one working example of it, you can quickly find the issues by differencing it with a broken version. To do this, you should create two Crawler instances (one working, and one not). You can then "subtract" these objects to reveal the differences.

a = Object(...)
b = Object(...)

crawl_a = Crawler(a)
crawl_b = Crawler(b)

print(crawl_a - crawl_b)

This will print out two joined tables with the differences highlighted in red.

Debug

If you don't trust the output there exists a debug mode for the print which can help you figure out what's going on.

To activate this we should create the actual Crawler object and store it in a variable:

crawl = Crawler(c)

We can then print the info using the print() method. This can take extra args, including debug

crawl.print(debug=True)
────────────────────┬───────────────────────────────────────────┬───────────────┬───────────────┬───────────────────┬───────────────────┬───────────
assignment          │ value                                     │ classname     │ source        │ entity            │ parent            │ nchildren
────────────────────┼───────────────────────────────────────────┼───────────────┼───────────────┼───────────────────┼───────────────────┼───────────
~                   │ <__main__.Meal object at 0x762f4d65de10>  │ Meal          │ None          │ Entity #47004730  │ None              │ 2
├─ name             │ Cheesy Beans on Toast                     │ str           │ Meal          │ Entity #91735648  │ Entity #47004730  │ 0
└─ ingredients      │ iterable: list                            │ list          │ Meal          │ Entity #43691166  │ Entity #47004730  │ 3
│  ├─ 0             │ Food(Cheese)                              │ Food          │ Meal          │ Entity #27979510  │ Entity #43691166  │ 1
│  │  └─ name       │ Cheese                                    │ str           │ Food          │ Entity #27472819  │ Entity #27979510  │ 0
│  ├─ 1             │ PreparedFood(Beans, 10)                   │ PreparedFood  │ Meal          │ Entity #62084209  │ Entity #43691166  │ 2
│  │  ├─ prep_time  │ 10                                        │ int           │ PreparedFood  │ Entity #04848920  │ Entity #62084209  │ 0
│  │  └─ name       │ Beans                                     │ str           │ Food          │ Entity #13535757  │ Entity #62084209  │ 0
│  └─ 2             │ PreparedFood(Toast, 5)                    │ PreparedFood  │ Meal          │ Entity #55272230  │ Entity #43691166  │ 2
│  │  ├─ prep_time  │ 5                                         │ int           │ PreparedFood  │ Entity #32701778  │ Entity #55272230  │ 0
│  │  └─ name       │ Toast                                     │ str           │ Food          │ Entity #67167938  │ Entity #55272230  │ 0

Debug output

To understand what we're seeing here it can be helpful to know what's going on inside this table.

Each row is represented by an Entity object. This stores some information about each attribute of the original object, but most importantly it stores the hierarchy of children.

The extra columns added expose this information.

The entity column contains part of the hash for the Entity in that row.

The parent column contains part of the hash for the Entity that provided the Entity in that row.

The nchildren column is a counter of how many children that entity has, and is used for tree generation.

Formatting

Similar to the debug, print() can also take some basic formatting arguments, whitespace and branch_len.

whitespace dictates the amount of padding added to the end of each column, whereas branch_len controls the length of each "branch" in the tree.

The best way to understand these args is to demonstrate them:

whitespace

crawl.print(whitespace=10)
────────────────────────────┬───────────────────────────────────────────────────┬───────────────────────┬───────────────────────
assignment                  │ value                                             │ classname             │ source
────────────────────────────┼───────────────────────────────────────────────────┼───────────────────────┼───────────────────────
~                           │ <__main__.Meal object at 0x762f4d65de10>          │ Meal                  │ None
├─ name                     │ Cheesy Beans on Toast                             │ str                   │ Meal
└─ ingredients              │ iterable: list                                    │ list                  │ Meal
│  ├─ 0                     │ Food(Cheese)                                      │ Food                  │ Meal
│  │  └─ name               │ Cheese                                            │ str                   │ Food
│  ├─ 1                     │ PreparedFood(Beans, 10)                           │ PreparedFood          │ Meal
│  │  ├─ prep_time          │ 10                                                │ int                   │ PreparedFood
│  │  └─ name               │ Beans                                             │ str                   │ Food
│  └─ 2                     │ PreparedFood(Toast, 5)                            │ PreparedFood          │ Meal
│  │  ├─ prep_time          │ 5                                                 │ int                   │ PreparedFood
│  │  └─ name               │ Toast                                             │ str                   │ Food


branch_len

crawl.print(branch_len=4)
─────────────────────────────┬───────────────────────────────────────────┬───────────────┬───────────────
assignment                   │ value                                     │ classname     │ source
─────────────────────────────┼───────────────────────────────────────────┼───────────────┼───────────────
~                            │ <__main__.Meal object at 0x762f4d65de10>  │ Meal          │ None
├──── name                   │ Cheesy Beans on Toast                     │ str           │ Meal
└──── ingredients            │ iterable: list                            │ list          │ Meal
│     ├──── 0                │ Food(Cheese)                              │ Food          │ Meal
│     │     └──── name       │ Cheese                                    │ str           │ Food
│     ├──── 1                │ PreparedFood(Beans, 10)                   │ PreparedFood  │ Meal
│     │     ├──── prep_time  │ 10                                        │ int           │ PreparedFood
│     │     └──── name       │ Beans                                     │ str           │ Food
│     └──── 2                │ PreparedFood(Toast, 5)                    │ PreparedFood  │ Meal
│     │     ├──── prep_time  │ 5                                         │ int           │ PreparedFood
│     │     └──── name       │ Toast                                     │ str           │ Food


Metadata

Release files for objectcrawler 0.0.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for objectcrawler 0.0.2
File Size Uploaded Provenance
objectcrawler-0.0.2.tar.gz 12.5 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for objectcrawler 0.0.2
File Interpreter ABI Platform
objectcrawler-0.0.2-py3-none-any.whl Python 3 none any Details

Total release size: 22.5 kB

Release files / objectcrawler-0.0.2.tar.gz

Download URL objectcrawler-0.0.2.tar.gz
Size 12.5 kB
Tags Source
SHA-256 checksum
How to use checksums
c28b50ed3e13a029dfb0331d6541afc9bf1e7f8ea6eaf5f77a045c50ee0b6100
BLAKE2b-256 checksum
How to use checksums
74eaad13d4bf7bf00e97aa7bc7a5d1004af48b72122a44c772e5af620f221f12
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/5.0.0 CPython/3.9.19

Release files / objectcrawler-0.0.2-py3-none-any.whl

Download URL objectcrawler-0.0.2-py3-none-any.whl
Size 10.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ab2cdc7a86e976f3c95d227b8254eaf3277d963641671ee78425204bade609d3
BLAKE2b-256 checksum
How to use checksums
bf3da199d767f7faa61ab73bd332bb358f663c647a45b89abf6ccf6a0166ffc6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/5.0.0 CPython/3.9.19

Security for objectcrawler 0.0.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.0.2 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page