Skip to content

Commit

Permalink
monkay integration (#229)
Browse files Browse the repository at this point in the history
Changes:

- use Monkay for settings, extensions and cli instance tracking
- tests lazy imports and imports
- make EdgyExtra and Migrate deprecated stubs, with Migrate keeping its model_apps system 
- fix get_engine_url_and_metadata
- fix typos and include @tarsild suggestions
- bump version
- update release notes and docs
  • Loading branch information
devkral authored Nov 16, 2024
1 parent 3146ac2 commit 848cad7
Show file tree
Hide file tree
Showing 78 changed files with 941 additions and 1,353 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ results/
site/
target/
tests/cli/migrations
tests/cli/migrations2
media/
test_media/

Expand Down
15 changes: 10 additions & 5 deletions docs/edgy-people.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
# Edgy People
# Edgy Contributors

## The Special Ones

Currently there are no special ones but we are hoping this will change soon.
Edgy wouldn't be possible in this way without these people.

## The Legends
- @kokoserver (https://github.com/Kokoserver)

Currently there are no legends but we are hoping this will change soon.
He provided a lot of valuable bug reports and PRs. Especially related to migrations.


- @devkral (https://github.com/devkral)

He refactored an reworked edgy nearly completely. Some features he provided are
FileFields, Registry hooks, copying models...
18 changes: 18 additions & 0 deletions docs/extensions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Extensions

Edgy has extension support build on the Monkay extensions system. Adding extensions
is possible in settings via the attribute/parameter `extensions`.

They must implement the monkay extension protocol or return as a callable a class implementing the extension protocol.
This sounds hard but it isn't:

``` python
{!> ../docs_src/extensions/settings !}
```

You can also lazily provide them via add_extension (should happen before the instance is set)


``` python
{!> ../docs_src/extensions/add_extension !}
```
59 changes: 0 additions & 59 deletions docs/extras.md

This file was deleted.

53 changes: 24 additions & 29 deletions docs/migrations/discovery.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,19 +61,17 @@ When no `--app` or no `EDGY_DEFAULT_APP` environment variable is provided, Edgy
* **main.py**
* **app.py**
* **application.py**
* **asgi.py**

(Or are otherwise importable by python without the .py stem)

!!! Warning
**If none of these files are found**, Edgy will look **at the first children nodes, only**,
and repeats the same process. If no files are found then throws an `CommandEnvironmentError`
exception.

* Once one of those files is found, Edgy will analised the type of objects contained in the
module and will check if any of them contains the `Migration` object attached and return it.

* If Edgy understand that none of those objects contain the `Migration`, it will
do one last attempt and try to find specific function declarations:
* **get_application()**
* **get_app()**
* Once one of those files is found, Edgy will check if the instance was set.

This is the way that Edgy can `auto discover` your application.

Expand All @@ -84,33 +82,21 @@ This is the way that Edgy can `auto discover` your application.

## Environment variables

When generating migrations, Edgy **expects at least one environment variable to be present**.
When generating migrations, Edgy can use two variables to detect the right database.

* **EDGY_DATABASE_URL** - The database url for your database.
* **EDGY_DATABASE** - The extra database name for your database.

By default the default database is used.

The reason for this is because Edgy is agnostic to any framework and this way it makes it easier
to work with the `migrations`.

Also, gives a clean design for the time where it is needed to go to production as the procedure is
very likely to be done using environment variables.

**This variable must be present**. So to save time you can simply do:

```
$ export EDGY_DATABASE_URL=postgresql+asyncpg://user:pass@localhost:5432/my_database
```

Or whatever connection string you are using.

Alternatively, you can simply pass `--app` as a parameter with the location of your application
instead.

Example:

```shell
$ edgy --app myproject.main:app init
```

## How to use and when to use it

Previously it was used a folder structure as example and then an explanation of how Edgy would
Expand Down Expand Up @@ -178,23 +164,32 @@ We will be also executing the commands inside `myproject`.
$ edgy init
```

Yes! Simply this and because the `--app` or a `EDGY_DEFAULT_APP` was provided, it triggered the
Yes! Simply this and because not the `--app` or a `EDGY_DEFAULT_APP` was provided nor preloads were found, it triggered the
auto discovery of the application that contains the edgy information.

Because the application is inside `src/main.py` it will be automatically discovered by Edgy as
it followed the [discovery pattern](#how-does-it-work).

##### Using the --app or EDGY_DISCOVERY_APP
##### Using preloads

Edgy has an automatic registration pattern. All what `--app` or `EDGY_DEFAULT_APP` does is to import a file.
The registration is expected to take place in the module automatically.
Thanks to Monkay you can also provide such an import path as preload under
`preloads` in settings.
When the instance is set in a preloaded file, the auto-discovery is skipped.


##### Using the --app or EDGY_DEFAULT_APP

This is the other way to tell Edgy where to find your application. Since the application is
inside the `src/main.py` we need to provide the proper location is a `<module>:<app>` format.
inside the `src/main.py` we need to provide the proper location is a `<module>` format.

###### --app

With the `--app` flag.

```shell
$ edgy --app src.main:app init
$ edgy --app src.main init
```

###### EDGY_DEFAULT_APP
Expand All @@ -204,7 +199,7 @@ With the `EDGY_DEFAULT_APP`.
Export the env var first:

```shell
$ export EDGY_DEFAULT_APP=src.main:app
$ export EDGY_DEFAULT_APP=src.main
```

And then run:
Expand Down Expand Up @@ -235,7 +230,7 @@ it triggered the auto discovery of the application.
With the `--app` flag.

```shell
$ edgy --app src.main:app makemigrations
$ edgy --app src.main makemigrations
```

###### EDGY_DEFAULT_APP
Expand All @@ -245,7 +240,7 @@ With the `EDGY_DEFAULT_APP`.
Export the env var first:

```shell
$ export EDGY_DEFAULT_APP=src.main:app
$ export EDGY_DEFAULT_APP=src.main
```

And then run:
Expand Down
79 changes: 30 additions & 49 deletions docs/migrations/migrations.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,37 +72,39 @@ This makes Edgy unique and extremely flexible to be used within any of the Frame
such as [Esmerald](https://esmerald.dymmond.com), Starlette, FastAPI, Sanic... You choose.

```python
from edgy import Migrate
from edgy import Instance, monkay

monkay.set_instance(Instance(registry=registry, app=None))
```

### Parameters

The parameters availabe when using instantiating a [Migrate](#migration) object are the following:
The parameters availabe when using instantiating a [Instance](#migration) object are the following:

* **app** - The application instance. Any application you want your migrations to be attached to.
* **registry** - The registry being used for your models. The registry **must be** an instance
of `edgy.Registry` or an `AssertationError` is raised.
* **model_apps** - A dictionary like object containing the string name and the location of the models
used for inspection.
* **compare_type** - Flag option that configures the automatic migration generation subsystem
to detect column type changes.
* **app** - Optionally an application instance.

<sup>Default: `True`</sup>
### Settings

* **render_as_batch** - This option generates migration scripts using batch mode, an operational
mode that works around limitations of many ALTER commands in the SQLite database by implementing
a "move and copy" workflow. Enabling this mode should make no difference when working with other
databases.
The following settings are available in the main settings object:

<sup>Default: `True`</sup>
- multi_schema (bool / regexstring / regexpattern) - Activate multi schema migrations (Default: False).
- ignore_schema_pattern (None / regexstring / regexpattern) - When using multi schema migrations, ignore following regex pattern (Default "information_schema")
- alembic_ctx_kwargs (dict) - Extra arguments for alembic. By default:
``` python
{
"compare_type": True,
"render_as_batch": True,
}
```
- migration_directory (str / PathLike) - Migrations directory. Absolute or relative. By default: "migrations".

* **kwargs** - A python dictionary with any context variables to be added to alembic.

<sup>Default: `None`</sup>

### How to use it

Using the [Migration](#migration) class is very simple in terms of requirements. In the
Using the [Instance](#migration) class is very simple in terms of requirements. In the
[tips and tricks](../tips-and-tricks.md) you can see some examples in terms of using the
[LRU cache technique](../tips-and-tricks.md#the-lru-cache). If you haven't seen it,
it is recommended you to have a look.
Expand Down Expand Up @@ -215,32 +217,11 @@ There is where your models for the `accounts` application will be placed. Someth
{!> ../docs_src/migrations/accounts_models.py !}
```

Now we want to tell the **Migrate** object to make sure it knows about this.

##### Via dictionary

```python
{!> ../docs_src/migrations/via_dict.py !}
```

As you can see the `model_apps = {"accounts": "accounts.models"}` was added in a simple fashion.
Every time you add new model or any changes, it should behave as normal as before with the key difference
that **now Edgy has a way to know exactly where your models are specifically**.

##### Via tuple

```python
{!> ../docs_src/migrations/via_tuple.py !}
```

The same for the tuple. You can simply pass `("accounts.models",)` as the location for the models.

##### Via list
Now we want to tell the **Instance** object to make sure it knows about this.

```python
{!> ../docs_src/migrations/via_list.py !}
{!> ../docs_src/migrations/instance.py !}
```
Finally, for the `list`. You can pass `["accounts.models"]` as the location for the models.

## Generating and working with migrations

Expand Down Expand Up @@ -327,28 +308,28 @@ $ export EDGY_DATABASE_URL=postgresql+asyncpg://user:pass@localhost:5432/my_data

Or whatever connection string you are using.

### Initialise the migrations folder
### Initialize the migrations folder

It is now time to generate the migrations folder. As mentioned before in the
[environment variables section](#environment-variables), Edgy does need to have the
`EDGY_DATABASE_URL` to generate the `migrations` folder. So, without further ado let us generate
our `migrations`.

```shell
edgy --app myproject.main:app init
edgy --app myproject.main init
```

What is happenening here? Well, `edgy` is always expecting an `--app` parameter to be
provided.

This `--app` is the location of your application in `module:app` format and this is because of
This `--app` is the location of your application in `module_app` format and this is because of
the fact of being **framework agnostic**.

Edgy needs to know where your application object is located in order to hook it to that same
application.
Edgy needs the module automatically setting the instance (see [Connections](connection.md)) to know the registry
which shall be used as well as the application object.

Remember when it was mentioned that is important the location where you generate the migrations
folder? Well, this is why, because when you do `my_project.main:app` you are telling that
folder? Well, this is why, because when you do `my_project.main` you are telling that
your application is inside the `myproject/main/app.py` and your migration folder should be placed
**where the command was executed**.

Expand Down Expand Up @@ -454,7 +435,7 @@ There are many ways of exposing your models of course, so feel free to use any a
Now it is time to generate the migration.

```shell
$ edgy --app my_project.main:app makemigrations
$ edgy --app my_project.main makemigrations
```

Yes, it is this simple 😁
Expand All @@ -479,7 +460,7 @@ Your new migration should now be inside `migrations/versions/`. Something like t
Or you can attach a message your migration that will then added to the file name as well.

```shell
$ edgy --app my_project.main:app makemigrations -m "Initial migrations"
$ edgy --app my_project.main makemigrations -m "Initial migrations"
```

```shell hl_lines="10"
Expand Down Expand Up @@ -519,13 +500,13 @@ for any other ORM and when you are happy run the migrations and apply them again
**Generate new migrations**

```shell
$ edgy --app my_project.main:app makemigrations
$ edgy --app my_project.main makemigrations
```

**Apply them to your database**

```shell
$ edgy --app my_project.main:app migrate
$ edgy --app my_project.main migrate
```

### More migration commands
Expand Down
Loading

0 comments on commit 848cad7

Please sign in to comment.