pyneo4j-ogm


Namepyneo4j-ogm JSON
Version 0.6.0 PyPI version JSON
download
home_pagehttps://github.com/groc-prog/pyneo4j-ogm
SummaryAsynchronous Python OGM for Neo4j
upload_time2024-05-23 09:47:34
maintainergroc-prog
docs_urlNone
authorgroc-prog
requires_python<4.0,>=3.10
licenseMIT
keywords neo4j python orm ogm async asynchronous database graph-database pydantic
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # pyneo4j-ogm

[![PyPI](https://img.shields.io/pypi/v/pyneo4j-ogm?style=flat-square)](https://pypi.org/project/pyneo4j-ogm/)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pyneo4j-ogm?style=flat-square)](https://pypi.org/project/pyneo4j-ogm/)
[![PyPI - License](https://img.shields.io/pypi/l/pyneo4j-ogm?style=flat-square)](https://pypi.org/project/pyneo4j-ogm/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/pyneo4j-ogm?style=flat-square)](https://pypi.org/project/pyneo4j-ogm/)

[`pyneo4j-ogm`](https://github.com/groc-prog/pyneo4j-ogm/blob/develop) is a asynchronous `Object-Graph-Mapper` for [`Neo4j 5+`](https://neo4j.com/docs/) and [`Python 3.10+`](https://www.python.org/). It is inspired by [`beanie`](https://github.com/roman-right/beanie) and build on top of proven technologies like [`Pydantic 1.10+ and 2+`](https://docs.pydantic.dev/latest/) and the [`Neo4j Python Driver`](https://neo4j.com/docs/api/python-driver/current/index.html). It saves you from writing ever-repeating boilerplate queries and allows you to focus on the `stuff that actually matters`. It is designed to be simple and easy to use, but also flexible and powerful.

## 🎯 Features

[`pyneo4j-ogm`](https://github.com/groc-prog/pyneo4j-ogm/blob/develop) has a lot to offer, including:

- [x] **Fully typed**: pyneo4j-ogm is `fully typed` out of the box.
- [x] **Powerful validation**: Since we use Pydantic under the hood, you can use it's powerful validation and serialization features without any issues.
- [x] **Focus on developer experience**: Designed to be simple to use, pyneo4j-ogm provides features for both simple queries and more `advanced use-cases` while keeping it's API as simple as possible.
- [x] **Build-in migration tooling**: Shipped with simple, yet flexible migration tooling.
- [x] **Fully asynchronous**: Completely asynchronous code, thanks to the `Neo4j Python Driver`.
- [x] **Supports Neo4j 5+**: pyneo4j-ogm supports `Neo4j 5+` and is tested against the latest version of Neo4j.
- [x] **Multi-version Pydantic support**: Both `Pydantic 1.10+` and `2+` fully supported.

## 📣 Announcements

Things to come in the future. Truly exiting stuff! If you have feature requests which you think might improve `pyneo4j-ogm`, feel free to open up a feature request.

- [ ] [MemGraph](https://memgraph.com/) support.

## 📦 Installation

Using [`pip`](https://pip.pypa.io/en/stable/):

```bash
pip install pyneo4j-ogm
```

or when using [`Poetry`](https://python-poetry.org/):

```bash
poetry add pyneo4j-ogm
```

## 🚀 Quickstart

Before we can get going, we have to take care of some things:

- We need to define our models, which will represent the nodes and relationships inside our database.
- We need a database client, which will do the actual work for us.

### Defining our data structures

Since every developer has a coffee addiction one way or another, we are going to use `Coffee` and `Developers` for this guide. So let's start by defining what our data should look like:

```python
from pyneo4j_ogm import (
    NodeModel,
    RelationshipModel,
    RelationshipProperty,
    RelationshipPropertyCardinality,
    RelationshipPropertyDirection,
    WithOptions,
)
from pydantic import Field
from uuid import UUID, uuid4


class Developer(NodeModel):
  """
  This class represents a `Developer` node inside the graph. All interactions
  with nodes of this type will be handled by this class.
  """
  uid: WithOptions(UUID, unique=True) = Field(default_factory=uuid4)
  name: str
  age: int

  coffee: RelationshipProperty["Coffee", "Consumed"] = RelationshipProperty(
    target_model="Coffee",
    relationship_model="Consumed",
    direction=RelationshipPropertyDirection.OUTGOING,
    cardinality=RelationshipPropertyCardinality.ZERO_OR_MORE,
    allow_multiple=True,
  )

  class Settings:
    # Hooks are available for all methods that interact with the database.
    post_hooks = {
      "coffee.connect": lambda self, *args, **kwargs: print(f"{self.name} chugged another one!")
    }


class Coffee(NodeModel):
  """
  This class represents a node with the labels `Beverage` and `Hot`. Notice
  that the labels of this model are explicitly defined in the `Settings` class.
  """
  flavor: str
  sugar: bool
  milk: bool

  developers: RelationshipProperty["Developer", "Consumed"] = RelationshipProperty(
    target_model=Developer,
    relationship_model="Consumed",
    direction=RelationshipPropertyDirection.INCOMING,
    cardinality=RelationshipPropertyCardinality.ZERO_OR_MORE,
    allow_multiple=True,
  )

  class Settings:
    labels = {"Beverage", "Hot"}

class Consumed(RelationshipModel):
  """
  Unlike the models above, this class represents a relationship between two
  nodes. In this case, it represents the relationship between the `Developer`
  and `Coffee` models. Like with node-models, the `Settings` class allows us to
  define some configuration for this relationship.

  Note that the relationship itself does not define it's start- and end-nodes,
  making it reusable for other models as well.
  """
  liked: bool

  class Settings:
    type = "CHUGGED"
```

Until now everything seems pretty standard if you have worked with other ORM's before. But if you haven't, we are going to go over what happened above:

- We defined 2 node models `Developer` and `Coffee`, and a relationship `Consumed`.
- Some models define a special inner `Settings` class. This is used to customize the behavior of our models inside the graph. More on these settings can be found [`here`](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#configuration-settings).
- The `WithOptions` function has been used to define `constraints and indexes` (more about them [`here`](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/DatabaseClient.md#manual-indexing-and-constraints)) on model properties.

### Creating a database client

In pyneo4j-ogm, the real work is done by a database client. One of these bad-boys can be created by initializing a `Pyneo4jClient` instance. But for models to work as expected, we have to let our client know that we want to use them like so:

```python
from pyneo4j_ogm import Pyneo4jClient

async def main():
  # We initialize a new `Pyneo4jClient` instance and connect to the database.
  client = Pyneo4jClient()

  # Replace `<connection-uri-to-database>`, `<username>` and `<password>` with the
  # actual values.
  await client.connect(uri="<connection-uri-to-database>", auth=("<username>", "<password>"))

  # To use our models for running queries later on, we have to register
  # them with the client.
  # **Note**: You only have to register the models that you want to use
  # for queries and you can even skip this step if you want to use the
  # `Pyneo4jClient` instance for running raw queries.
  await client.register_models([Developer, Coffee, Consumed])
```

### Interacting with the database

Now the fun stuff begins! We are ready to interact with our database. For the sake of this [`quickstart guide`](https://github.com/groc-prog/pyneo4j-ogm/blob/develop?tab=readme-ov-file#-quickstart) we are going to keep it nice and simple, but this is just the surface of what pyneo4j-ogm has to offer.

We are going to create a new `Developer` and some `Coffee` and give him something to drink:

```python
# Imagine your models have been defined above...

async def main():
  # And your client has been initialized and connected to the database...

  # We create a new `Developer` node and the `Coffee` he is going to drink.
  john = Developer(name="John", age=25)
  await john.create()

  cappuccino = Coffee(flavor="Cappuccino", milk=True, sugar=False)
  await cappuccino.create()

  # Here we create a new relationship between `john` and his `cappuccino`.
  # Additionally, we set the `liked` property of the relationship to `True`.
  await john.coffee.connect(cappuccino, {"liked": True}) # Will print `John chugged another one!`
```

### Full example

```python
import asyncio
from pyneo4j_ogm import (
    NodeModel,
    Pyneo4jClient,
    RelationshipModel,
    RelationshipProperty,
    RelationshipPropertyCardinality,
    RelationshipPropertyDirection,
    WithOptions,
)
from pydantic import Field
from uuid import UUID, uuid4

class Developer(NodeModel):
  """
  This class represents a `Developer` node inside the graph. All interaction
  with nodes of this type will be handled by this class.
  """
  uid: WithOptions(UUID, unique=True) = Field(default_factory=uuid4)
  name: str
  age: int

  coffee: RelationshipProperty["Coffee", "Consumed"] = RelationshipProperty(
    target_model="Coffee",
    relationship_model="Consumed",
    direction=RelationshipPropertyDirection.OUTGOING,
    cardinality=RelationshipPropertyCardinality.ZERO_OR_MORE,
    allow_multiple=True,
  )

  class Settings:
    # Hooks are available for all methods that interact with the database.
    post_hooks = {
      "coffee.connect": lambda self, *args, **kwargs: print(f"{self.name} chugged another one!")
    }


class Coffee(NodeModel):
  """
  This class represents a node with the labels `Beverage` and `Hot`. Notice
  that the labels of this model are explicitly defined in the `Settings` class.
  """
  flavor: str
  sugar: bool
  milk: bool

  developers: RelationshipProperty["Developer", "Consumed"] = RelationshipProperty(
    target_model=Developer,
    relationship_model="Consumed",
    direction=RelationshipPropertyDirection.INCOMING,
    cardinality=RelationshipPropertyCardinality.ZERO_OR_MORE,
    allow_multiple=True,
  )

  class Settings:
    labels = {"Beverage", "Hot"}

class Consumed(RelationshipModel):
  """
  Unlike the models above, this class represents a relationship between two
  nodes. In this case, it represents the relationship between the `Developer`
  and `Coffee` models. Like with node-models, the `Settings` class allows us to
  define some settings for this relationship.

  Note that the relationship itself does not define it's start- and end-nodes,
  making it reusable for other models as well.
  """
  liked: bool

  class Settings:
    type = "CHUGGED"


async def main():
  # We initialize a new `Pyneo4jClient` instance and connect to the database.
  client = Pyneo4jClient()
  await client.connect(uri="<connection-uri-to-database>", auth=("<username>", "<password>"))

  # To use our models for running queries later on, we have to register
  # them with the client.
  # **Note**: You only have to register the models that you want to use
  # for queries and you can even skip this step if you want to use the
  # `Pyneo4jClient` instance for running raw queries.
  await client.register_models([Developer, Coffee, Consumed])

  # We create a new `Developer` node and the `Coffee` he is going to drink.
  john = Developer(name="John", age=25)
  await john.create()

  cappuccino = Coffee(flavor="Cappuccino", milk=True, sugar=False)
  await cappuccino.create()

  # Here we create a new relationship between `john` and his `cappuccino`.
  # Additionally, we set the `liked` property of the relationship to `True`.
  await john.coffee.connect(cappuccino, {"liked": True}) # Will print `John chugged another one!`

  # Be a good boy and close your connections after you are done.
  await client.close()

asyncio.run(main())
```

And that's it! You should now see a `Developer` and a `Hot/Beverage` node, connected by a `CONSUMED` relationship. If you want to learn more about the library, you can check out the full [`Documentation`](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs).

## 📚 Documentation

In the following we are going to take a closer look at the different parts of `pyneo4j-ogm` and how to use them. We will cover everything pyneo4j-ogm has to offer, from the `Pyneo4jClient` to the `NodeModel` and `RelationshipModel` classes all the way to the `Query filters` and `Auto-fetching relationship-properties`.

### Table of contents

- [pyneo4j-ogm](https://github.com/groc-prog/pyneo4j-ogm/blob/develop?tab=readme-ov-file#pyneo4j-ogm)
  - [🎯 Features](https://github.com/groc-prog/pyneo4j-ogm/blob/develop?tab=readme-ov-file#features)
  - [📣 Announcements](https://github.com/groc-prog/pyneo4j-ogm/blob/develop?tab=readme-ov-file#-announcements)
  - [📦 Installation](https://github.com/groc-prog/pyneo4j-ogm/blob/develop?tab=readme-ov-file#-installation)
  - [🚀 Quickstart](https://github.com/groc-prog/pyneo4j-ogm/blob/develop?tab=readme-ov-file#-quickstart)
    - [Defining our data structures](https://github.com/groc-prog/pyneo4j-ogm/blob/develop?tab=readme-ov-file#-defining-our-data-structures)
    - [Creating a database client](https://github.com/groc-prog/pyneo4j-ogm/blob/develop?tab=readme-ov-file#-creating-a-database-client)
    - [Interacting with the database](https://github.com/groc-prog/pyneo4j-ogm/blob/develop?tab=readme-ov-file#-interacting-with-the-database)
    - [Full example](https://github.com/groc-prog/pyneo4j-ogm/blob/develop?tab=readme-ov-file#-full-example)
  - [Running the test suite](https://github.com/groc-prog/pyneo4j-ogm/blob/develop?tab=readme-ov-file#-running-the-test-suite)
  - [📚 Documentation](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs)
    - [Basic concepts](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Concept.md)
      - [A note on Pydantic version support](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Concept.md#a-note-on-pydantic-version-support)
    - [Database client](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/DatabaseClient.md)
      - [Connecting to the database](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/DatabaseClient.md#connecting-to-the-database)
      - [Closing an existing connection](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/DatabaseClient.md#closing-an-existing-connection)
      - [Registering models](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/DatabaseClient.md#registering-models)
      - [Executing Cypher queries](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/DatabaseClient.md#executing-cypher-queries)
      - [Batching cypher queries](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/DatabaseClient.md#batching-cypher-queries)
      - [Using bookmarks (Enterprise Edition only)](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/DatabaseClient.md#using-bookmarks-enterprise-edition-only)
      - [Manual indexing and constraints](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/DatabaseClient.md#manual-indexing-and-constraints)
      - [Client utilities](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/DatabaseClient.md#client-utilities)
    - [Models](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md)
      - [Indexes, constraints and properties](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#indexes-constraints-and-properties)
      - [Reserved properties](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#reserved-properties)
      - [Configuration settings](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#configuration-settings)
        - [NodeModel configuration](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#nodemodel-configuration)
        - [RelationshipModel configuration](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#relationshipmodel-configuration)
      - [Available methods](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#available-methods)
        - [Instance.update()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#instanceupdate)
        - [Instance.delete()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#instancedelete)
        - [Instance.refresh()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#instancerefresh)
        - [Model.find_one()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#modelfind_one)
        - [Model.find_many()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#modelfind_many)
        - [Model.update_one()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#modelupdate_one)
        - [Model.update_many()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#modelupdate_many)
        - [Model.delete_one()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#modeldelete_one)
        - [Model.delete_many()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#modeldelete_many)
        - [Model.count()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#modelcount)
        - [NodeModelInstance.create()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#nodemodelinstancecreate)
        - [NodeModelInstance.find_connected_nodes()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#nodemodelinstancefind_connected_nodes)
        - [RelationshipModelInstance.start_node()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#relationshipmodelinstancestart_node)
        - [RelationshipModelInstance.end_node()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#relationshipmodelinstanceend_node)
      - [Serializing models](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#serializing-models)
      - [Hooks](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#hooks)
        - [Pre-hooks](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#pre-hooks)
        - [Post-hooks](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#post-hooks)
      - [Model settings](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#model-settings)
    - [Relationship-properties](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/RelationshipProperty.md)
      - [Available methods](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/RelationshipProperty.md#available-methods)
        - [RelationshipProperty.relationships()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/RelationshipProperty.md#relationshippropertyrelationships)
        - [RelationshipProperty.connect()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/RelationshipProperty.md#relationshippropertyconnect)
        - [RelationshipProperty.disconnect()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/RelationshipProperty.md#relationshippropertydisconnect)
        - [RelationshipProperty.disconnect\_all()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/RelationshipProperty.md#relationshippropertydisconnect_all)
        - [RelationshipProperty.replace()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/RelationshipProperty.md#relationshippropertyreplace)
        - [RelationshipProperty.find\_connected\_nodes()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/RelationshipProperty.md#relationshippropertyfind_connected_nodes)
      - [Hooks with relationship properties](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/RelationshipProperty.md#hooks-with-relationship-properties)
    - [Queries](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Query.md)
      - [Filtering queries](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Query.md#filtering-queries)
        - [Comparison operators](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Query.md#comparison-operators)
        - [String operators](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Query.md#string-operators)
        - [List operators](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Query.md#list-operators)
        - [Logical operators](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Query.md#logical-operators)
        - [Element operators](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Query.md#element-operators)
        - [Pattern matching](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Query.md#pattern-matching)
        - [Multi-hop filters](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Query.md#multi-hop-filters)
      - [Projections](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Query.md#projections)
      - [Query options](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Query.md#query-options)
      - [Auto-fetching relationship-properties](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Query.md#auto-fetching-relationship-properties)
    - [Migrations](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Migrations.md)
      - [Initializing migrations for your project](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Migrations.md#initializing-migrations-for-your-project)
      - [Creating a new migration](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Migrations.md#creating-a-new-migration)
      - [Running migrations](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Migrations.md#running-migrations)
      - [Listing migrations](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Migrations.md#listing-migrations)
      - [Programmatic usage](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Migrations.md#programmatic-usage)
    - [Logging](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Logging.md)

### Running the test suite

To run the test suite, you have to install the development dependencies and run the tests using `pytest`. The tests are located in the `tests` directory. Some tests will require you to have a Neo4j instance running on `localhost:7687` with the credentials (`neo4j:password`). This can easily be done using the provided `docker-compose.yml` file.

```bash
poetry run pytest tests --asyncio-mode=auto -W ignore::DeprecationWarning
```

> **Note:** The `-W ignore::DeprecationWarning` can be omitted but will result in a lot of deprication warnings by Neo4j itself about the usage of the now deprecated `ID`.

As for running the tests with a different pydantic version, you can just install a different pydantic version with the following command:

```bash
poetry add pydantic@<version>
```


            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/groc-prog/pyneo4j-ogm",
    "name": "pyneo4j-ogm",
    "maintainer": "groc-prog",
    "docs_url": null,
    "requires_python": "<4.0,>=3.10",
    "maintainer_email": "marc.troisner@gmail.com",
    "keywords": "neo4j, python, orm, ogm, async, asynchronous, database, graph-database, pydantic",
    "author": "groc-prog",
    "author_email": "marc.troisner@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/05/c9/44a4568fe444440fef2725c8b39bedfc11325960e2375776b2d3d937dacb/pyneo4j_ogm-0.6.0.tar.gz",
    "platform": null,
    "description": "# pyneo4j-ogm\n\n[![PyPI](https://img.shields.io/pypi/v/pyneo4j-ogm?style=flat-square)](https://pypi.org/project/pyneo4j-ogm/)\n[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pyneo4j-ogm?style=flat-square)](https://pypi.org/project/pyneo4j-ogm/)\n[![PyPI - License](https://img.shields.io/pypi/l/pyneo4j-ogm?style=flat-square)](https://pypi.org/project/pyneo4j-ogm/)\n[![PyPI - Downloads](https://img.shields.io/pypi/dm/pyneo4j-ogm?style=flat-square)](https://pypi.org/project/pyneo4j-ogm/)\n\n[`pyneo4j-ogm`](https://github.com/groc-prog/pyneo4j-ogm/blob/develop) is a asynchronous `Object-Graph-Mapper` for [`Neo4j 5+`](https://neo4j.com/docs/) and [`Python 3.10+`](https://www.python.org/). It is inspired by [`beanie`](https://github.com/roman-right/beanie) and build on top of proven technologies like [`Pydantic 1.10+ and 2+`](https://docs.pydantic.dev/latest/) and the [`Neo4j Python Driver`](https://neo4j.com/docs/api/python-driver/current/index.html). It saves you from writing ever-repeating boilerplate queries and allows you to focus on the `stuff that actually matters`. It is designed to be simple and easy to use, but also flexible and powerful.\n\n## \ud83c\udfaf Features\n\n[`pyneo4j-ogm`](https://github.com/groc-prog/pyneo4j-ogm/blob/develop) has a lot to offer, including:\n\n- [x] **Fully typed**: pyneo4j-ogm is `fully typed` out of the box.\n- [x] **Powerful validation**: Since we use Pydantic under the hood, you can use it's powerful validation and serialization features without any issues.\n- [x] **Focus on developer experience**: Designed to be simple to use, pyneo4j-ogm provides features for both simple queries and more `advanced use-cases` while keeping it's API as simple as possible.\n- [x] **Build-in migration tooling**: Shipped with simple, yet flexible migration tooling.\n- [x] **Fully asynchronous**: Completely asynchronous code, thanks to the `Neo4j Python Driver`.\n- [x] **Supports Neo4j 5+**: pyneo4j-ogm supports `Neo4j 5+` and is tested against the latest version of Neo4j.\n- [x] **Multi-version Pydantic support**: Both `Pydantic 1.10+` and `2+` fully supported.\n\n## \ud83d\udce3 Announcements\n\nThings to come in the future. Truly exiting stuff! If you have feature requests which you think might improve `pyneo4j-ogm`, feel free to open up a feature request.\n\n- [ ] [MemGraph](https://memgraph.com/) support.\n\n## \ud83d\udce6 Installation\n\nUsing [`pip`](https://pip.pypa.io/en/stable/):\n\n```bash\npip install pyneo4j-ogm\n```\n\nor when using [`Poetry`](https://python-poetry.org/):\n\n```bash\npoetry add pyneo4j-ogm\n```\n\n## \ud83d\ude80 Quickstart\n\nBefore we can get going, we have to take care of some things:\n\n- We need to define our models, which will represent the nodes and relationships inside our database.\n- We need a database client, which will do the actual work for us.\n\n### Defining our data structures\n\nSince every developer has a coffee addiction one way or another, we are going to use `Coffee` and `Developers` for this guide. So let's start by defining what our data should look like:\n\n```python\nfrom pyneo4j_ogm import (\n    NodeModel,\n    RelationshipModel,\n    RelationshipProperty,\n    RelationshipPropertyCardinality,\n    RelationshipPropertyDirection,\n    WithOptions,\n)\nfrom pydantic import Field\nfrom uuid import UUID, uuid4\n\n\nclass Developer(NodeModel):\n  \"\"\"\n  This class represents a `Developer` node inside the graph. All interactions\n  with nodes of this type will be handled by this class.\n  \"\"\"\n  uid: WithOptions(UUID, unique=True) = Field(default_factory=uuid4)\n  name: str\n  age: int\n\n  coffee: RelationshipProperty[\"Coffee\", \"Consumed\"] = RelationshipProperty(\n    target_model=\"Coffee\",\n    relationship_model=\"Consumed\",\n    direction=RelationshipPropertyDirection.OUTGOING,\n    cardinality=RelationshipPropertyCardinality.ZERO_OR_MORE,\n    allow_multiple=True,\n  )\n\n  class Settings:\n    # Hooks are available for all methods that interact with the database.\n    post_hooks = {\n      \"coffee.connect\": lambda self, *args, **kwargs: print(f\"{self.name} chugged another one!\")\n    }\n\n\nclass Coffee(NodeModel):\n  \"\"\"\n  This class represents a node with the labels `Beverage` and `Hot`. Notice\n  that the labels of this model are explicitly defined in the `Settings` class.\n  \"\"\"\n  flavor: str\n  sugar: bool\n  milk: bool\n\n  developers: RelationshipProperty[\"Developer\", \"Consumed\"] = RelationshipProperty(\n    target_model=Developer,\n    relationship_model=\"Consumed\",\n    direction=RelationshipPropertyDirection.INCOMING,\n    cardinality=RelationshipPropertyCardinality.ZERO_OR_MORE,\n    allow_multiple=True,\n  )\n\n  class Settings:\n    labels = {\"Beverage\", \"Hot\"}\n\nclass Consumed(RelationshipModel):\n  \"\"\"\n  Unlike the models above, this class represents a relationship between two\n  nodes. In this case, it represents the relationship between the `Developer`\n  and `Coffee` models. Like with node-models, the `Settings` class allows us to\n  define some configuration for this relationship.\n\n  Note that the relationship itself does not define it's start- and end-nodes,\n  making it reusable for other models as well.\n  \"\"\"\n  liked: bool\n\n  class Settings:\n    type = \"CHUGGED\"\n```\n\nUntil now everything seems pretty standard if you have worked with other ORM's before. But if you haven't, we are going to go over what happened above:\n\n- We defined 2 node models `Developer` and `Coffee`, and a relationship `Consumed`.\n- Some models define a special inner `Settings` class. This is used to customize the behavior of our models inside the graph. More on these settings can be found [`here`](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#configuration-settings).\n- The `WithOptions` function has been used to define `constraints and indexes` (more about them [`here`](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/DatabaseClient.md#manual-indexing-and-constraints)) on model properties.\n\n### Creating a database client\n\nIn pyneo4j-ogm, the real work is done by a database client. One of these bad-boys can be created by initializing a `Pyneo4jClient` instance. But for models to work as expected, we have to let our client know that we want to use them like so:\n\n```python\nfrom pyneo4j_ogm import Pyneo4jClient\n\nasync def main():\n  # We initialize a new `Pyneo4jClient` instance and connect to the database.\n  client = Pyneo4jClient()\n\n  # Replace `<connection-uri-to-database>`, `<username>` and `<password>` with the\n  # actual values.\n  await client.connect(uri=\"<connection-uri-to-database>\", auth=(\"<username>\", \"<password>\"))\n\n  # To use our models for running queries later on, we have to register\n  # them with the client.\n  # **Note**: You only have to register the models that you want to use\n  # for queries and you can even skip this step if you want to use the\n  # `Pyneo4jClient` instance for running raw queries.\n  await client.register_models([Developer, Coffee, Consumed])\n```\n\n### Interacting with the database\n\nNow the fun stuff begins! We are ready to interact with our database. For the sake of this [`quickstart guide`](https://github.com/groc-prog/pyneo4j-ogm/blob/develop?tab=readme-ov-file#-quickstart) we are going to keep it nice and simple, but this is just the surface of what pyneo4j-ogm has to offer.\n\nWe are going to create a new `Developer` and some `Coffee` and give him something to drink:\n\n```python\n# Imagine your models have been defined above...\n\nasync def main():\n  # And your client has been initialized and connected to the database...\n\n  # We create a new `Developer` node and the `Coffee` he is going to drink.\n  john = Developer(name=\"John\", age=25)\n  await john.create()\n\n  cappuccino = Coffee(flavor=\"Cappuccino\", milk=True, sugar=False)\n  await cappuccino.create()\n\n  # Here we create a new relationship between `john` and his `cappuccino`.\n  # Additionally, we set the `liked` property of the relationship to `True`.\n  await john.coffee.connect(cappuccino, {\"liked\": True}) # Will print `John chugged another one!`\n```\n\n### Full example\n\n```python\nimport asyncio\nfrom pyneo4j_ogm import (\n    NodeModel,\n    Pyneo4jClient,\n    RelationshipModel,\n    RelationshipProperty,\n    RelationshipPropertyCardinality,\n    RelationshipPropertyDirection,\n    WithOptions,\n)\nfrom pydantic import Field\nfrom uuid import UUID, uuid4\n\nclass Developer(NodeModel):\n  \"\"\"\n  This class represents a `Developer` node inside the graph. All interaction\n  with nodes of this type will be handled by this class.\n  \"\"\"\n  uid: WithOptions(UUID, unique=True) = Field(default_factory=uuid4)\n  name: str\n  age: int\n\n  coffee: RelationshipProperty[\"Coffee\", \"Consumed\"] = RelationshipProperty(\n    target_model=\"Coffee\",\n    relationship_model=\"Consumed\",\n    direction=RelationshipPropertyDirection.OUTGOING,\n    cardinality=RelationshipPropertyCardinality.ZERO_OR_MORE,\n    allow_multiple=True,\n  )\n\n  class Settings:\n    # Hooks are available for all methods that interact with the database.\n    post_hooks = {\n      \"coffee.connect\": lambda self, *args, **kwargs: print(f\"{self.name} chugged another one!\")\n    }\n\n\nclass Coffee(NodeModel):\n  \"\"\"\n  This class represents a node with the labels `Beverage` and `Hot`. Notice\n  that the labels of this model are explicitly defined in the `Settings` class.\n  \"\"\"\n  flavor: str\n  sugar: bool\n  milk: bool\n\n  developers: RelationshipProperty[\"Developer\", \"Consumed\"] = RelationshipProperty(\n    target_model=Developer,\n    relationship_model=\"Consumed\",\n    direction=RelationshipPropertyDirection.INCOMING,\n    cardinality=RelationshipPropertyCardinality.ZERO_OR_MORE,\n    allow_multiple=True,\n  )\n\n  class Settings:\n    labels = {\"Beverage\", \"Hot\"}\n\nclass Consumed(RelationshipModel):\n  \"\"\"\n  Unlike the models above, this class represents a relationship between two\n  nodes. In this case, it represents the relationship between the `Developer`\n  and `Coffee` models. Like with node-models, the `Settings` class allows us to\n  define some settings for this relationship.\n\n  Note that the relationship itself does not define it's start- and end-nodes,\n  making it reusable for other models as well.\n  \"\"\"\n  liked: bool\n\n  class Settings:\n    type = \"CHUGGED\"\n\n\nasync def main():\n  # We initialize a new `Pyneo4jClient` instance and connect to the database.\n  client = Pyneo4jClient()\n  await client.connect(uri=\"<connection-uri-to-database>\", auth=(\"<username>\", \"<password>\"))\n\n  # To use our models for running queries later on, we have to register\n  # them with the client.\n  # **Note**: You only have to register the models that you want to use\n  # for queries and you can even skip this step if you want to use the\n  # `Pyneo4jClient` instance for running raw queries.\n  await client.register_models([Developer, Coffee, Consumed])\n\n  # We create a new `Developer` node and the `Coffee` he is going to drink.\n  john = Developer(name=\"John\", age=25)\n  await john.create()\n\n  cappuccino = Coffee(flavor=\"Cappuccino\", milk=True, sugar=False)\n  await cappuccino.create()\n\n  # Here we create a new relationship between `john` and his `cappuccino`.\n  # Additionally, we set the `liked` property of the relationship to `True`.\n  await john.coffee.connect(cappuccino, {\"liked\": True}) # Will print `John chugged another one!`\n\n  # Be a good boy and close your connections after you are done.\n  await client.close()\n\nasyncio.run(main())\n```\n\nAnd that's it! You should now see a `Developer` and a `Hot/Beverage` node, connected by a `CONSUMED` relationship. If you want to learn more about the library, you can check out the full [`Documentation`](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs).\n\n## \ud83d\udcda Documentation\n\nIn the following we are going to take a closer look at the different parts of `pyneo4j-ogm` and how to use them. We will cover everything pyneo4j-ogm has to offer, from the `Pyneo4jClient` to the `NodeModel` and `RelationshipModel` classes all the way to the `Query filters` and `Auto-fetching relationship-properties`.\n\n### Table of contents\n\n- [pyneo4j-ogm](https://github.com/groc-prog/pyneo4j-ogm/blob/develop?tab=readme-ov-file#pyneo4j-ogm)\n  - [\ud83c\udfaf Features](https://github.com/groc-prog/pyneo4j-ogm/blob/develop?tab=readme-ov-file#features)\n  - [\ud83d\udce3 Announcements](https://github.com/groc-prog/pyneo4j-ogm/blob/develop?tab=readme-ov-file#-announcements)\n  - [\ud83d\udce6 Installation](https://github.com/groc-prog/pyneo4j-ogm/blob/develop?tab=readme-ov-file#-installation)\n  - [\ud83d\ude80 Quickstart](https://github.com/groc-prog/pyneo4j-ogm/blob/develop?tab=readme-ov-file#-quickstart)\n    - [Defining our data structures](https://github.com/groc-prog/pyneo4j-ogm/blob/develop?tab=readme-ov-file#-defining-our-data-structures)\n    - [Creating a database client](https://github.com/groc-prog/pyneo4j-ogm/blob/develop?tab=readme-ov-file#-creating-a-database-client)\n    - [Interacting with the database](https://github.com/groc-prog/pyneo4j-ogm/blob/develop?tab=readme-ov-file#-interacting-with-the-database)\n    - [Full example](https://github.com/groc-prog/pyneo4j-ogm/blob/develop?tab=readme-ov-file#-full-example)\n  - [Running the test suite](https://github.com/groc-prog/pyneo4j-ogm/blob/develop?tab=readme-ov-file#-running-the-test-suite)\n  - [\ud83d\udcda Documentation](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs)\n    - [Basic concepts](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Concept.md)\n      - [A note on Pydantic version support](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Concept.md#a-note-on-pydantic-version-support)\n    - [Database client](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/DatabaseClient.md)\n      - [Connecting to the database](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/DatabaseClient.md#connecting-to-the-database)\n      - [Closing an existing connection](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/DatabaseClient.md#closing-an-existing-connection)\n      - [Registering models](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/DatabaseClient.md#registering-models)\n      - [Executing Cypher queries](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/DatabaseClient.md#executing-cypher-queries)\n      - [Batching cypher queries](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/DatabaseClient.md#batching-cypher-queries)\n      - [Using bookmarks (Enterprise Edition only)](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/DatabaseClient.md#using-bookmarks-enterprise-edition-only)\n      - [Manual indexing and constraints](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/DatabaseClient.md#manual-indexing-and-constraints)\n      - [Client utilities](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/DatabaseClient.md#client-utilities)\n    - [Models](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md)\n      - [Indexes, constraints and properties](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#indexes-constraints-and-properties)\n      - [Reserved properties](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#reserved-properties)\n      - [Configuration settings](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#configuration-settings)\n        - [NodeModel configuration](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#nodemodel-configuration)\n        - [RelationshipModel configuration](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#relationshipmodel-configuration)\n      - [Available methods](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#available-methods)\n        - [Instance.update()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#instanceupdate)\n        - [Instance.delete()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#instancedelete)\n        - [Instance.refresh()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#instancerefresh)\n        - [Model.find_one()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#modelfind_one)\n        - [Model.find_many()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#modelfind_many)\n        - [Model.update_one()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#modelupdate_one)\n        - [Model.update_many()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#modelupdate_many)\n        - [Model.delete_one()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#modeldelete_one)\n        - [Model.delete_many()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#modeldelete_many)\n        - [Model.count()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#modelcount)\n        - [NodeModelInstance.create()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#nodemodelinstancecreate)\n        - [NodeModelInstance.find_connected_nodes()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#nodemodelinstancefind_connected_nodes)\n        - [RelationshipModelInstance.start_node()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#relationshipmodelinstancestart_node)\n        - [RelationshipModelInstance.end_node()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#relationshipmodelinstanceend_node)\n      - [Serializing models](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#serializing-models)\n      - [Hooks](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#hooks)\n        - [Pre-hooks](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#pre-hooks)\n        - [Post-hooks](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#post-hooks)\n      - [Model settings](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Models.md#model-settings)\n    - [Relationship-properties](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/RelationshipProperty.md)\n      - [Available methods](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/RelationshipProperty.md#available-methods)\n        - [RelationshipProperty.relationships()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/RelationshipProperty.md#relationshippropertyrelationships)\n        - [RelationshipProperty.connect()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/RelationshipProperty.md#relationshippropertyconnect)\n        - [RelationshipProperty.disconnect()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/RelationshipProperty.md#relationshippropertydisconnect)\n        - [RelationshipProperty.disconnect\\_all()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/RelationshipProperty.md#relationshippropertydisconnect_all)\n        - [RelationshipProperty.replace()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/RelationshipProperty.md#relationshippropertyreplace)\n        - [RelationshipProperty.find\\_connected\\_nodes()](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/RelationshipProperty.md#relationshippropertyfind_connected_nodes)\n      - [Hooks with relationship properties](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/RelationshipProperty.md#hooks-with-relationship-properties)\n    - [Queries](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Query.md)\n      - [Filtering queries](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Query.md#filtering-queries)\n        - [Comparison operators](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Query.md#comparison-operators)\n        - [String operators](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Query.md#string-operators)\n        - [List operators](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Query.md#list-operators)\n        - [Logical operators](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Query.md#logical-operators)\n        - [Element operators](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Query.md#element-operators)\n        - [Pattern matching](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Query.md#pattern-matching)\n        - [Multi-hop filters](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Query.md#multi-hop-filters)\n      - [Projections](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Query.md#projections)\n      - [Query options](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Query.md#query-options)\n      - [Auto-fetching relationship-properties](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Query.md#auto-fetching-relationship-properties)\n    - [Migrations](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Migrations.md)\n      - [Initializing migrations for your project](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Migrations.md#initializing-migrations-for-your-project)\n      - [Creating a new migration](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Migrations.md#creating-a-new-migration)\n      - [Running migrations](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Migrations.md#running-migrations)\n      - [Listing migrations](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Migrations.md#listing-migrations)\n      - [Programmatic usage](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Migrations.md#programmatic-usage)\n    - [Logging](https://github.com/groc-prog/pyneo4j-ogm/blob/develop/docs/Logging.md)\n\n### Running the test suite\n\nTo run the test suite, you have to install the development dependencies and run the tests using `pytest`. The tests are located in the `tests` directory. Some tests will require you to have a Neo4j instance running on `localhost:7687` with the credentials (`neo4j:password`). This can easily be done using the provided `docker-compose.yml` file.\n\n```bash\npoetry run pytest tests --asyncio-mode=auto -W ignore::DeprecationWarning\n```\n\n> **Note:** The `-W ignore::DeprecationWarning` can be omitted but will result in a lot of deprication warnings by Neo4j itself about the usage of the now deprecated `ID`.\n\nAs for running the tests with a different pydantic version, you can just install a different pydantic version with the following command:\n\n```bash\npoetry add pydantic@<version>\n```\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Asynchronous Python OGM for Neo4j",
    "version": "0.6.0",
    "project_urls": {
        "Documentation": "https://github.com/groc-prog/pyneo4j-ogm#readme",
        "Homepage": "https://github.com/groc-prog/pyneo4j-ogm",
        "Repository": "https://github.com/groc-prog/pyneo4j-ogm"
    },
    "split_keywords": [
        "neo4j",
        " python",
        " orm",
        " ogm",
        " async",
        " asynchronous",
        " database",
        " graph-database",
        " pydantic"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "876703513cee90c2cea295aa21d7c5d0900e636e06a75e650612d4a01fe860f4",
                "md5": "71c0d1aa6060e4b8ff3019dab48331fa",
                "sha256": "c56722aa787e89e81df7ea9f5517bab0c6820a981be55784475a18f53fda954d"
            },
            "downloads": -1,
            "filename": "pyneo4j_ogm-0.6.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "71c0d1aa6060e4b8ff3019dab48331fa",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.10",
            "size": 68299,
            "upload_time": "2024-05-23T09:47:32",
            "upload_time_iso_8601": "2024-05-23T09:47:32.507640Z",
            "url": "https://files.pythonhosted.org/packages/87/67/03513cee90c2cea295aa21d7c5d0900e636e06a75e650612d4a01fe860f4/pyneo4j_ogm-0.6.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "05c944a4568fe444440fef2725c8b39bedfc11325960e2375776b2d3d937dacb",
                "md5": "d319543b581c8132b844f21efdaffdf1",
                "sha256": "c384b78e187dd7acdf5572942264d07532401c39e5c27f7c9535b0c2fe106e23"
            },
            "downloads": -1,
            "filename": "pyneo4j_ogm-0.6.0.tar.gz",
            "has_sig": false,
            "md5_digest": "d319543b581c8132b844f21efdaffdf1",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.10",
            "size": 61652,
            "upload_time": "2024-05-23T09:47:34",
            "upload_time_iso_8601": "2024-05-23T09:47:34.407304Z",
            "url": "https://files.pythonhosted.org/packages/05/c9/44a4568fe444440fef2725c8b39bedfc11325960e2375776b2d3d937dacb/pyneo4j_ogm-0.6.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-05-23 09:47:34",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "groc-prog",
    "github_project": "pyneo4j-ogm",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "pyneo4j-ogm"
}
        
Elapsed time: 0.40659s