ideas icon indicating copy to clipboard operation
ideas copied to clipboard

Django URLconf type checker

Open spookylukey opened this issue 2 years ago • 10 comments

Project description

Given some URLs configured like this (as per the Django docs):

# urls.py
from django.urls import path

from . import views

urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    path('articles/<int:year>/', views.year_archive),
    path('articles/<int:year>/<int:month>/', views.month_archive),
    path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
]

And some views like this:

# views.py

def special_case(request):
    pass

def year_archive(request, year: int):
    pass

def month_archive(request, year: int, month: int):
    pass

def article_detail(request, year: int, month: int, slug: str):
    pass

...we can check that the types of parameters match. So, for example, if we changed one of these but forget to change the other, we'd be immediately be notified, instead of waiting for runtime errors or test failures.

The good thing about this - I've already written a big chunk of the code! You can find it here: https://github.com/spookylukey/django-views-the-right-way/blob/master/code/the_right_way/url_checker.py . I've started using this code in some real projects, but it needs work, and I think it could be useful to a lot of people in the Django community.

What is missing is:

  • tests
  • docs
  • packaging - i.e. making a nice, easy to install and use package out of this.
  • cleaning up the code
  • missing features mentioned in the code

Relevant Technology

You need experience with Django and Python. Very advanced knowledge is not needed, but it will introduce you to introspection and type annotations if you don't have that knowledge already. The main skills used/developed will be to do with testing, documentation and package management.

Complexity and required time

Complexity

  • [ ] Beginner - This project requires no or little prior knowledge of the technologies specified to contribute to the project
  • [x] Intermediate - The user should have some prior knowledge of the technologies to the point where they know how to use it, but not necessarily all the nooks and crannies of the technology
  • [ ] Advanced - The project requires the user to have a good understanding of all components of the project to contribute

This is easily small enough to be managed by a single person, and will get your feet wet with running a small project.

Required time (ETA)

  • [ ] Little work - A couple of days
  • [x] Medium work - A week or two
  • [ ] Much work - The project will take more than a couple of weeks and serious planning is required

The bare minimum to get this project packaged could be done in a couple of days, but I think the project could benefit from tests, docs etc. which would take longer.

Categories

  • [ ] Mobile app
  • [ ] IoT
  • [ ] Web app
  • [ ] Frontend/UI
  • [ ] AI/ML
  • [ ] APIs/Backend
  • [ ] Voice Assistant
  • [x] Developer Tooling
  • [ ] Extension/Plugin/Add-On
  • [ ] Design/UX
  • [ ] AR/VR
  • [ ] Bots
  • [ ] Security
  • [ ] Blockchain
  • [ ] Futuristic Tech/Something Unique

Help/guidance

I'm happy to give help/suggestions for anyone interested but needing some pointers with any aspects.

spookylukey avatar Sep 15 '21 09:09 spookylukey

@spookylukey Hi there! This seems to be a great idea, and I want to help out. How do you recommend proceeding?

AliSayyah avatar Jan 27 '22 00:01 AliSayyah

@AliSayyah Thanks for your interest!

I'm assuming you already know some Python and Django - if not, this project might not be for you.

This is how I would go about it:

  1. Copy the code I linked above, and see if you can get it working in the context of Django project - this won't be the final home, just an initial test so that you can see the pieces.
  2. Start a new repo and project for the code. You might want to use cookie-cutter to get you started. Since this will be a library that uses Django, rather than a Django application, I'd recommend using a Python library template, not the "Cookiecutter Django" template which is for a Django project.
  3. Add the code, and start writing some tests. You need to pick a test framework - probably pytest and pytest-django would be best, but you can also use the normal unittest style that is in the Django docs. At this point, I wouldn't try to write all the possible tests, a few will do. The hardest will be working out how to write them, especially since this library is a bit unusual - all it does is emit "checks" at development time, rather than do anything at runtime. Look at existing projects that use Django checks and see how they write tests. Maybe Django itself - see https://github.com/django/django/blob/main/tests/check_framework/test_urls.py
  4. Try to get a package published on PyPI - it will be a 0.0.1 version at this point, that's fine, you are going to be the only one who uses it. You'll need the Python Packaging User Guide
  5. Install the package in some other Django project and try to use it. At this point you will write the installation docs, and possibly discover that it doesn't work, or you messed up the packaging etc.
  6. Install Sphinx and build the docs, then get them working on readthedocs.org
  7. Iterate on the above - code, tests, docs, packaging - until you have something ready for the world to see.

A quick look at your GitHub contributions makes me think you will not be lost with all of the above, but some of these steps could be hard if you've never done them before. I'm happy to try and help if you get stuck.

In addition: the following are not necessary, especially if you are overwhelmed by all this, but at some point I would highly recommend:

  • set up CI - I would recommend GitHub Actions rather than Travis (the template above uses TravisCI). There are quite a few Python packages you can copy workflows from e.g. django-money. Also the zllionare/cookiecutter-pypackage/ is another template you can copy workflows from (see .github/workflows).
  • use black, isort, flake8
  • set up pre-commit in your repo, which can run the above tools for you when you commit

spookylukey avatar Jan 27 '22 21:01 spookylukey

I wonder why not to generate them from function prototypes instead of checking?

KOLANICH avatar Jan 28 '22 07:01 KOLANICH

@spookylukey Thank you for your explanations🙏 I`ll keep you updated about the process.

AliSayyah avatar Jan 28 '22 08:01 AliSayyah

@KOLANICH Could you please explain more?

AliSayyah avatar Jan 28 '22 08:01 AliSayyah

I wonder why not to generate them from function prototypes instead of checking?

That wouldn't solve the problem of them getting out of sync. In other frameworks, URLs and view functions are closer together, like in Flask, but in Django they are separated.

spookylukey avatar Jan 28 '22 15:01 spookylukey

# urls.py
from django.urls import path

from . import views

urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    path('articles/{}/', views.year_archive),
    path('articles/{}/{}/', views.month_archive),
    path('articles/{}/{}/{}/', views.article_detail),
# or
    path('articles/{slash_delimited}', views.article_detail), #magic name
]

# views.py

def special_case(request):
    pass

def year_archive(request, year: int):
    pass

def month_archive(request, year: int, month: int):
    pass

def article_detail(request, year: int, month: int, slug: slug):
    pass

KOLANICH avatar Jan 28 '22 20:01 KOLANICH

I created the repository and required workflows. I would appreciate any feedback. https://github.com/AliSayyah/django-urlconf-checks

AliSayyah avatar Jan 29 '22 08:01 AliSayyah

@spookylukey hey! https://pypi.org/project/django-urlconfchecks/ the package is now functional. I'll start working on better tests and TODOs. Thank you for your assistance. https://github.com/AliSayyah/django-urlconfchecks/discussions/23 Can you please join me in this discussion?

AliSayyah avatar Feb 05 '22 06:02 AliSayyah

Hey, this looks brilliant! 🎉️

I'll join that discussion.

spookylukey avatar Feb 07 '22 09:02 spookylukey