Falldog / pyconcrete

Protect your python script, encrypt it as .pye and decrypt when import it
Apache License 2.0
692 stars 149 forks source link

Management commands error after protect in Django #107

Closed sfcl closed 2 months ago

sfcl commented 3 months ago

Django doesn't see commands executed from the command line using the manage.py script protected by the pyconcrete package.

There is an operating system: Ubuntu 22.04.4 LTS x86_64 Interpreter: Python 3.10.12 Packages installed: Django==5.0.6, pyconcrete==0.15.1 Installed compiler: apt-get install gcc python3-dev

To reproduce the error, we used a simple Django project https://github.com/deparkes/simple-django-app. Next, a simple management command is created in the file counter/management/commands/inventory.py

Its contents are very simple:

from django.core.management.base import BaseCommand

class Command(BaseCommand):
    help = 'Command example: ./manage.py inventory'

    def handle(self, *args, **options):
        print('Hello, World!')

Executable files were protected with the command:

pyconcrete-admin.py compile --source=counter --pye  --remove-py  --remove-pyc 

After protecting the files, the manage.py script stopped seeing the inventory command. Command line output:

Unknown command: 'inventory'
Type 'manage.py help' for usage.

Please advise how to solve the problem?

Falldog commented 3 months ago

FYI, here is a workable example for django, https://github.com/Falldog/pyconcrete/tree/master/example/django

For your case, I think that you need to make sure 2 things as below

  1. The entry point manage.py need to add import pyconcrete
  2. For your django commands, need to make sure it is workable even if pyconcrete is non installed. For example, counter/management/commands/ folder need to include __init__.py.
sfcl commented 3 months ago

Screenshot before running the program pyconcrete-admin.py compile

1

As you can see, the inventory command is present.

Here is the result of the program python manage.py inventory

2

After execution pyconcrete-admin.py compile management the command has disappeared.

3

I added import pyconcrete to the manage.py file.

Here are its contents:

(venv) root@3000745-cs84966:~/venv/simple-django-app/cool_counters# cat manage.py 
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys

import pyconcrete

def main():
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'cool_counters.settings')
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn't import Django. Are you sure it's installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc
    execute_from_command_line(sys.argv)

if __name__ == '__main__':
    main()

counter application directory structure

(venv) root@3000745-cs84966:~/venv/simple-django-app/cool_counters# tree counter
counter
├── admin.pye
├── apps.pye
├── __init__.pye
├── management
│   ├── commands
│   │   ├── __init__.pye
│   │   ├── inventory.pye
│   │   └── __pycache__
│   │       ├── __init__.cpython-310.pyc
│   │       └── inventory.cpython-310.pyc
│   ├── __init__.pye
│   └── __pycache__
│       └── __init__.cpython-310.pyc
├── migrations
│   ├── 0001_initial.pye
│   ├── __init__.pye
│   └── __pycache__
│       ├── 0001_initial.cpython-310.pyc
│       └── __init__.cpython-310.pyc
├── models.pye
├── __pycache__
│   ├── admin.cpython-310.pyc
│   ├── apps.cpython-310.pyc
│   ├── __init__.cpython-310.pyc
│   ├── models.cpython-310.pyc
│   ├── urls.cpython-310.pyc
│   └── views.cpython-310.pyc
├── templates
│   └── counter
│       └── index.html
├── tests.pye
├── urls.pye
└── views.pye

9 directories, 24 files

The web application also continues to run after the command is executed python manage.py runserver 0.0.0.0:9000.

4

But the error persists. Please help me resolve the error.

Falldog commented 3 months ago

It's a litter strange. Can you help to remove all of __pycache__ and then try it again?

sfcl commented 3 months ago

I cleared the python file cache with the command

find . | grep -E "(__pycache__|\.pyc|\.pyo$)" | xargs rm -rf

Result of the command python -B manage.py inventory

(venv) root@3001431-cs84966:~/venv/simple-django-app/cool_counters# python -B manage.py inventory
Unknown command: 'inventory'
Type 'manage.py help' for usage.

counter application directory structure

(venv) root@3001431-cs84966:~/venv/simple-django-app/cool_counters# tree counter/
counter/
├── admin.pye
├── apps.pye
├── __init__.pye
├── management
│   ├── commands
│   │   ├── __init__.pye
│   │   └── inventory.pye
│   └── __init__.pye
├── migrations
│   ├── 0001_initial.pye
│   └── __init__.pye
├── models.pye
├── templates
│   └── counter
│       └── index.html
├── tests.pye
├── urls.pye
└── views.pye

5 directories, 13 files

The error persists. Please help me resolve the error. I suggest that the author of the library reproduce the error on his computer to make sure that my words are correct.

My error is duplicate this issue

Falldog commented 3 months ago

I can reproduce this issue now. The root cause would be Django try to find command by pkgutil as below logic file: django/core/management/__init__.py

def find_commands(management_dir):
    """
    Given a path to a management directory, return a list of all the command
    names that are available.
    """
    command_dir = os.path.join(management_dir, "commands")
    return [
        name
        for _, name, is_pkg in pkgutil.iter_modules([command_dir])
        if not is_pkg and not name.startswith("_")
    ]

Current pyconcrete Metapath solution doesn't compatible with it. Need to implement path_hooks handler. I think it will need some time to add the feature.

dx-77 commented 2 months ago

@Falldog