simple object crawling debug tool
Project description
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
- Create a fork of this repo
- Clone the forked repo to your machine
- 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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file objectcrawler-0.0.2.tar.gz
.
File metadata
- Download URL: objectcrawler-0.0.2.tar.gz
- Upload date:
- Size: 12.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.0.0 CPython/3.9.19
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | c28b50ed3e13a029dfb0331d6541afc9bf1e7f8ea6eaf5f77a045c50ee0b6100 |
|
MD5 | 8e9c818a04aab82fd54199f266c65520 |
|
BLAKE2b-256 | 74eaad13d4bf7bf00e97aa7bc7a5d1004af48b72122a44c772e5af620f221f12 |
File details
Details for the file objectcrawler-0.0.2-py3-none-any.whl
.
File metadata
- Download URL: objectcrawler-0.0.2-py3-none-any.whl
- Upload date:
- Size: 10.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.0.0 CPython/3.9.19
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | ab2cdc7a86e976f3c95d227b8254eaf3277d963641671ee78425204bade609d3 |
|
MD5 | 5ba18163a4f081eb45ae18814699acc3 |
|
BLAKE2b-256 | bf3da199d767f7faa61ab73bd332bb358f663c647a45b89abf6ccf6a0166ffc6 |