objectcrawler


Nameobjectcrawler JSON
Version 0.0.2 PyPI version JSON
download
home_pageNone
Summarysimple object crawling debug tool
upload_time2024-04-15 13:36:29
maintainerNone
docs_urlNone
authorNone
requires_python>=3.7
licenseNone
keywords debug inspect inspection
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # 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:

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

### Demo

Lets demonstrate this with a simple class:

```python
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:

```python
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:

```python
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)

```python
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.

```python
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:

```python
crawl = Crawler(c)
```
We can then print the info using the `print()` method. This can take extra args, including `debug`

```python
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

```python
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

```python
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


```

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "objectcrawler",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": null,
    "keywords": "debug, inspect, inspection",
    "author": null,
    "author_email": "Louis Beal <louis.j.beal@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/74/ea/ad13d4bf7bf00e97aa7bc7a5d1004af48b72122a44c772e5af620f221f12/objectcrawler-0.0.2.tar.gz",
    "platform": null,
    "description": "# objectcrawler\n\nBasic and lightweight python tool for inspecting python objects.\n\nOriginally built for objects defining `__slots__`, however it also handles the `__dict__` attribute just fine.\n\n## Installation\n\n1) Create a fork of this repo\n2) Clone the forked repo to your machine\n3) Install with `pip install ObjectCrawler`\n\nFor development you can install using the pip `-e` editable flag.\n\nFeel free to file a pull request if you make any changes!\n\n## Usage\n\nInspecting an object is simple, import the `Crawler` class and feed it the object in question:\n\n```python\nfrom objectcrawler import Crawler\nprint(Crawler(...))\n```\n\n### Demo\n\nLets demonstrate this with a simple class:\n\n```python\nclass Food:\n    __slots__ = [\"name\"]\n    def __init__(self, name: str):\n        self.name = name\n\n    def __repr__(self):\n        return f\"Food({self.name})\"\n```\n\nAfter creating an instance of this class, we can inspect it:\n\n```python\nfrom objectcrawler import Crawler\na = Food(\"Apple\")\nprint(Crawler(a))\n```\n\nThis will output the following table:\n\n```\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nassignment  \u2502 value        \u2502 classname  \u2502 source\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n~           \u2502 Food(Apple)  \u2502 Food       \u2502 self\n\u2514\u2500 name     \u2502 Apple        \u2502 str        \u2502 Food\n```\n\n### Inheritance\n\nThe purpose of the `source` column is to display information about inheritance.\n\nIf we create a subclass, we can see this behaviour:\n\n```python\nclass PreparedFood(Food):\n    __slots__ = [\"prep_time\"]\n    def __init__(self, name: str, prep_time: int):\n        super().__init__(name)\n\n        self.prep_time = prep_time\n\n    def __repr__(self):\n        return f\"PreparedFood({self.name}, {self.prep_time})\"\n\nb = PreparedFood(\"Pasta\", 10)\nprint(Crawler(b))\n```\n\nGiving the following table. Note the `source` column:\n\n```\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nassignment    \u2502 value                    \u2502 classname     \u2502 source\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n~             \u2502 PreparedFood(Pasta, 10)  \u2502 PreparedFood  \u2502 None\n\u251c\u2500 prep_time  \u2502 10                       \u2502 int           \u2502 PreparedFood\n\u2514\u2500 name       \u2502 Pasta                    \u2502 str           \u2502 Food\n```\n\n### Iterators\n\nIterators are a special case, since they are implicit storage containers, an attempt is made to \"unpack\" them into the data tree.\n\nlists, tuples, etc. wil have their `assignment` set to the index\n\ndicts, OrderedDicts, etc. will have their `assignment` set to the key (the object must provide a `iter()` method for this functionality)\n\n```python\nclass Meal:\n    __slots__ = [\"name\", \"ingredients\"]\n    def __init__(self, name: str, ingredients: list):\n        self.name = name\n        self.ingredients = ingredients\n\ningredients = [\n    Food(\"Cheese\"),\n    PreparedFood(\"Beans\", 10),\n    PreparedFood(\"Toast\", 5)\n]\n\nc = Meal(\"Cheesy Beans on Toast\", ingredients)\nprint(Crawler(c))\n```\n\n```\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nassignment          \u2502 value                                     \u2502 classname     \u2502 source\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n~                   \u2502 <__main__.Meal object at 0x762f4d65de10>  \u2502 Meal          \u2502 None\n\u251c\u2500 name             \u2502 Cheesy Beans on Toast                     \u2502 str           \u2502 Meal\n\u2514\u2500 ingredients      \u2502 iterable: list                            \u2502 list          \u2502 Meal\n\u2502  \u251c\u2500 0             \u2502 Food(Cheese)                              \u2502 Food          \u2502 Meal\n\u2502  \u2502  \u2514\u2500 name       \u2502 Cheese                                    \u2502 str           \u2502 Food\n\u2502  \u251c\u2500 1             \u2502 PreparedFood(Beans, 10)                   \u2502 PreparedFood  \u2502 Meal\n\u2502  \u2502  \u251c\u2500 prep_time  \u2502 10                                        \u2502 int           \u2502 PreparedFood\n\u2502  \u2502  \u2514\u2500 name       \u2502 Beans                                     \u2502 str           \u2502 Food\n\u2502  \u2514\u2500 2             \u2502 PreparedFood(Toast, 5)                    \u2502 PreparedFood  \u2502 Meal\n\u2502  \u2502  \u251c\u2500 prep_time  \u2502 5                                         \u2502 int           \u2502 PreparedFood\n\u2502  \u2502  \u2514\u2500 name       \u2502 Toast                                     \u2502 str           \u2502 Food\n```\n\n## Differences\n\nIf 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.\n\n```python\na = Object(...)\nb = Object(...)\n\ncrawl_a = Crawler(a)\ncrawl_b = Crawler(b)\n\nprint(crawl_a - crawl_b)\n```\n\nThis will print out two joined tables with the differences highlighted in red.\n\n## Debug\n\nIf you don't trust the output there exists a debug mode for the print which can help you figure out what's going on.\n\nTo activate this we should create the actual `Crawler` object and store it in a variable:\n\n```python\ncrawl = Crawler(c)\n```\nWe can then print the info using the `print()` method. This can take extra args, including `debug`\n\n```python\ncrawl.print(debug=True)\n```\n\n```\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nassignment          \u2502 value                                     \u2502 classname     \u2502 source        \u2502 entity            \u2502 parent            \u2502 nchildren\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n~                   \u2502 <__main__.Meal object at 0x762f4d65de10>  \u2502 Meal          \u2502 None          \u2502 Entity #47004730  \u2502 None              \u2502 2\n\u251c\u2500 name             \u2502 Cheesy Beans on Toast                     \u2502 str           \u2502 Meal          \u2502 Entity #91735648  \u2502 Entity #47004730  \u2502 0\n\u2514\u2500 ingredients      \u2502 iterable: list                            \u2502 list          \u2502 Meal          \u2502 Entity #43691166  \u2502 Entity #47004730  \u2502 3\n\u2502  \u251c\u2500 0             \u2502 Food(Cheese)                              \u2502 Food          \u2502 Meal          \u2502 Entity #27979510  \u2502 Entity #43691166  \u2502 1\n\u2502  \u2502  \u2514\u2500 name       \u2502 Cheese                                    \u2502 str           \u2502 Food          \u2502 Entity #27472819  \u2502 Entity #27979510  \u2502 0\n\u2502  \u251c\u2500 1             \u2502 PreparedFood(Beans, 10)                   \u2502 PreparedFood  \u2502 Meal          \u2502 Entity #62084209  \u2502 Entity #43691166  \u2502 2\n\u2502  \u2502  \u251c\u2500 prep_time  \u2502 10                                        \u2502 int           \u2502 PreparedFood  \u2502 Entity #04848920  \u2502 Entity #62084209  \u2502 0\n\u2502  \u2502  \u2514\u2500 name       \u2502 Beans                                     \u2502 str           \u2502 Food          \u2502 Entity #13535757  \u2502 Entity #62084209  \u2502 0\n\u2502  \u2514\u2500 2             \u2502 PreparedFood(Toast, 5)                    \u2502 PreparedFood  \u2502 Meal          \u2502 Entity #55272230  \u2502 Entity #43691166  \u2502 2\n\u2502  \u2502  \u251c\u2500 prep_time  \u2502 5                                         \u2502 int           \u2502 PreparedFood  \u2502 Entity #32701778  \u2502 Entity #55272230  \u2502 0\n\u2502  \u2502  \u2514\u2500 name       \u2502 Toast                                     \u2502 str           \u2502 Food          \u2502 Entity #67167938  \u2502 Entity #55272230  \u2502 0\n```\n\n### Debug output\n\nTo understand what we're seeing here it can be helpful to know what's going on inside this table.\n\nEach 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.\n\nThe extra columns added expose this information.\n\nThe `entity` column contains part of the hash for the `Entity` in _that row_.\n\nThe `parent` column contains part of the hash for the `Entity` that _provided_ the `Entity` in that row.\n\nThe `nchildren` column is a counter of how many children that entity has, and is used for tree generation.\n\n## Formatting\n\nSimilar to the debug, `print()` can also take some basic formatting arguments, `whitespace` and `branch_len`.\n\n`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.\n\nThe best way to understand these args is to demonstrate them:\n\n### whitespace\n\n```python\ncrawl.print(whitespace=10)\n```\n\n```\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nassignment                  \u2502 value                                             \u2502 classname             \u2502 source\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n~                           \u2502 <__main__.Meal object at 0x762f4d65de10>          \u2502 Meal                  \u2502 None\n\u251c\u2500 name                     \u2502 Cheesy Beans on Toast                             \u2502 str                   \u2502 Meal\n\u2514\u2500 ingredients              \u2502 iterable: list                                    \u2502 list                  \u2502 Meal\n\u2502  \u251c\u2500 0                     \u2502 Food(Cheese)                                      \u2502 Food                  \u2502 Meal\n\u2502  \u2502  \u2514\u2500 name               \u2502 Cheese                                            \u2502 str                   \u2502 Food\n\u2502  \u251c\u2500 1                     \u2502 PreparedFood(Beans, 10)                           \u2502 PreparedFood          \u2502 Meal\n\u2502  \u2502  \u251c\u2500 prep_time          \u2502 10                                                \u2502 int                   \u2502 PreparedFood\n\u2502  \u2502  \u2514\u2500 name               \u2502 Beans                                             \u2502 str                   \u2502 Food\n\u2502  \u2514\u2500 2                     \u2502 PreparedFood(Toast, 5)                            \u2502 PreparedFood          \u2502 Meal\n\u2502  \u2502  \u251c\u2500 prep_time          \u2502 5                                                 \u2502 int                   \u2502 PreparedFood\n\u2502  \u2502  \u2514\u2500 name               \u2502 Toast                                             \u2502 str                   \u2502 Food\n\n\n```\n\n### branch_len\n\n```python\ncrawl.print(branch_len=4)\n```\n\n```\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nassignment                   \u2502 value                                     \u2502 classname     \u2502 source\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n~                            \u2502 <__main__.Meal object at 0x762f4d65de10>  \u2502 Meal          \u2502 None\n\u251c\u2500\u2500\u2500\u2500 name                   \u2502 Cheesy Beans on Toast                     \u2502 str           \u2502 Meal\n\u2514\u2500\u2500\u2500\u2500 ingredients            \u2502 iterable: list                            \u2502 list          \u2502 Meal\n\u2502     \u251c\u2500\u2500\u2500\u2500 0                \u2502 Food(Cheese)                              \u2502 Food          \u2502 Meal\n\u2502     \u2502     \u2514\u2500\u2500\u2500\u2500 name       \u2502 Cheese                                    \u2502 str           \u2502 Food\n\u2502     \u251c\u2500\u2500\u2500\u2500 1                \u2502 PreparedFood(Beans, 10)                   \u2502 PreparedFood  \u2502 Meal\n\u2502     \u2502     \u251c\u2500\u2500\u2500\u2500 prep_time  \u2502 10                                        \u2502 int           \u2502 PreparedFood\n\u2502     \u2502     \u2514\u2500\u2500\u2500\u2500 name       \u2502 Beans                                     \u2502 str           \u2502 Food\n\u2502     \u2514\u2500\u2500\u2500\u2500 2                \u2502 PreparedFood(Toast, 5)                    \u2502 PreparedFood  \u2502 Meal\n\u2502     \u2502     \u251c\u2500\u2500\u2500\u2500 prep_time  \u2502 5                                         \u2502 int           \u2502 PreparedFood\n\u2502     \u2502     \u2514\u2500\u2500\u2500\u2500 name       \u2502 Toast                                     \u2502 str           \u2502 Food\n\n\n```\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "simple object crawling debug tool",
    "version": "0.0.2",
    "project_urls": {
        "Documentation": "https://github.com/ljbeal/ObjectCrawler",
        "Homepage": "https://github.com/ljbeal/ObjectCrawler",
        "Issues": "https://github.com/ljbeal/ObjectCrawler/issues",
        "Repository": "https://github.com/ljbeal/ObjectCrawler"
    },
    "split_keywords": [
        "debug",
        " inspect",
        " inspection"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "bf3da199d767f7faa61ab73bd332bb358f663c647a45b89abf6ccf6a0166ffc6",
                "md5": "5ba18163a4f081eb45ae18814699acc3",
                "sha256": "ab2cdc7a86e976f3c95d227b8254eaf3277d963641671ee78425204bade609d3"
            },
            "downloads": -1,
            "filename": "objectcrawler-0.0.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "5ba18163a4f081eb45ae18814699acc3",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 10062,
            "upload_time": "2024-04-15T13:36:28",
            "upload_time_iso_8601": "2024-04-15T13:36:28.803712Z",
            "url": "https://files.pythonhosted.org/packages/bf/3d/a199d767f7faa61ab73bd332bb358f663c647a45b89abf6ccf6a0166ffc6/objectcrawler-0.0.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "74eaad13d4bf7bf00e97aa7bc7a5d1004af48b72122a44c772e5af620f221f12",
                "md5": "8e9c818a04aab82fd54199f266c65520",
                "sha256": "c28b50ed3e13a029dfb0331d6541afc9bf1e7f8ea6eaf5f77a045c50ee0b6100"
            },
            "downloads": -1,
            "filename": "objectcrawler-0.0.2.tar.gz",
            "has_sig": false,
            "md5_digest": "8e9c818a04aab82fd54199f266c65520",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 12469,
            "upload_time": "2024-04-15T13:36:29",
            "upload_time_iso_8601": "2024-04-15T13:36:29.942000Z",
            "url": "https://files.pythonhosted.org/packages/74/ea/ad13d4bf7bf00e97aa7bc7a5d1004af48b72122a44c772e5af620f221f12/objectcrawler-0.0.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-04-15 13:36:29",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "ljbeal",
    "github_project": "ObjectCrawler",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "objectcrawler"
}
        
Elapsed time: 0.24055s