3YOURMIND / django-deprecate-fields

This package allows deprecating model fields and allows removing them in a backwards compatible manner.
Apache License 2.0
177 stars 20 forks source link

Testing for migrations from sys.argv is too naive #18

Open intgr opened 3 years ago

intgr commented 3 years ago

Currently this project uses the following test to check whether we're migrating:

    if not set(sys.argv) & {"makemigrations", "migrate", "showmigrations"}:
        return DeprecatedField(return_instead)

This check can be too naive, however:

I haven't looked into better solutions yet, just letting you know of this problem.

flixx commented 3 years ago

Hi @intgr understood.

Probably additionally, something like this could be used to check if we are inside djangos migration module...

import inspect

def is_inside_migration():
    for frame_info in inspect.stack():
        if frame_info[1].endswith("django/db/migrations/autodetector.py"):
            return True
    return False

Not sure if django/db/migrations/autodetector.py would be the best choice though. Do you know a file that is for sure in the stack when running migrations?

intgr commented 3 years ago

I think that won't work. A bigger issue is that with this syntax:

class MyModel(models.Model):
    field1 = deprecate_field(models.CharField())

The deprecate_field() function is executed at import-time. Imports may come from arbitrary locations, at which time it's not known whether the field is going to be used for accessing data or migrating the schema. Indeed during the life of one Python process, like my test suite, it may be used both ways.

So I'm afraid returning different things based on a condition inside deprecate_field() function is not a good solution. You might have to return DeprecatedField always and do something conditional in there. But I'm guessing this brings more complications.

christianbundy commented 1 year ago

Could we use something simple like an environment variable for this? It's janky, but for folks who have complicated migrations configurations that aren't just ./manage.py migrate it might be useful to have an escape hatch.