Results 1 to 6 of 6

Thread: TypeError: missing 1 required positional argument (word counter Django app)

  1. #1
    Join Date
    May 2007
    Location
    Ontario
    Beans
    475
    Distro
    Ubuntu

    TypeError: missing 1 required positional argument (word counter Django app)

    I’ve got a Python script which counts and prints the number of words in a text file. The script runs beautifully. It takes a public domain book (a text file such as Alice and Wonderland) which then counts the top 10 most used words (but which also filters out stopwords). See here for some of my previous work.

    Now I am trying to ‘port’ this Python shell script to Django. My intention for this project is to have the Django app count the number of words in a blog post. But for now I’m still using Alice and Wonderland in .txt format.

    I’ve encountered some issues with my local dev server running but serving me a series of name errors involving my views module when I navigate to the url. I was hoping some of you could provide some insight.

    When I run the server and navigate to `http://127.0.0.1:8000/seth/`, this is the error showing in my web browser pointing to the issue at hand: https://pastebin.com/raw/52x2c4iN

    Here is the traceback from my local Django dev server in my shell: https://pastebin.com/raw/a8PTcRki

    The file with the most problems is my counters/views.py (current app only):

    Code:
    from django.http import HttpResponse, HttpResponseRedirect
    from django.shortcuts import render
    from collections import Counter
    from nltk.corpus import stopwords
    import re
    # from .forms import UploadFileForm
    from django.views.generic.edit import FormView
    from .forms import FileFieldForm
    
    text = None
    word = None
    
    class FileFieldView(FormView):
        form_class = FileFieldForm
        template_name = 'seth.html'  # Replace with your template.
        success_url = 'seth_success' # Replace with your URL or reverse().
    
        def post(self, request, *args, **kwargs):
            form_class = self.get_form_class()
            form = self.get_form(form_class)
            files = request.FILES.getlist('Alice.txt')
            if form.is_valid():
                for f in files:
                    global text
                    # Do something with each file. For example the following? Is what follows even valid?
                    text = f.read().lower()                
                return self.form_valid(form)
            else:
                return self.form_invalid(form)
    
    def counters(request, text):
        """
        This function processes the top 10 most common words and then renders them.
        """
        stoplist = stopwords.words('english')
        stoplist.extend(["said","gutenberg", "could", "would",]) 
        clean = []
        global word
        global count
        for word in re.split(r"\W+",text):
            if word not in stoplist:
                clean.append(word)
        top_10 = Counter(clean).most_common(10)
        for word,count in top_10:
            return render(request, 'counters/seth.html', {'word': word, 'count': count})
    
    def main(request):
        """
        This function calls the counters function
        """
        text = FileFieldView.post()
        run = counters(text)
    
    if __name__ == "__main__":
        main()
        pass
    I realize that the problem is with the way the text variable is tossed around. I probably should not be invoking global variables as I do at lines 24, 38, 39 in my views model (above). Furthermore, out of the Udemy course material I’ve watched and in the official Django docs I’ve read, I’ve never seen a views.py which uses main() for calling functions. I realize I am sort of departing from Django norms here. What might you people recommend I try instead?

    Here is counters/models.py:

    Code:
    from django.db import models
    from django import forms
    import datetime
    
    class UploadFileForm(forms.Form):
        title = forms.CharField(max_length=150)
        file = forms.FileField()
    
    class Count(models.Model):
        title = models.CharField(max_length=161)
        pub_date = models.DateTimeField()
        image = models.ImageField(upload_to='media/')
        body = models.TextField()
        now = datetime.datetime.now()
    
    class FileFieldForm(forms.Form):
        file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
    Here is counters/forms.py:

    Code:
    # With advice from this Django doc: https://docs.djangoproject.com/en/2..../file-uploads/
     
    from django import forms
    
    class UploadFileForm(forms.Form):
        title = forms.CharField(max_length=50)
        file = forms.FileField()
    
    class FileFieldForm(forms.Form):
        file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
    Here is urls.py in parent project directory:

    Code:
    from django.contrib import admin
    from django.urls import path, re_path
    # from . import views
    from posts.views import *
    from redactors.views import *
    from counters.views import *
    from AllAbove.views import *
    from django.conf.urls.static import static
    from django.conf import settings
    
    urlpatterns = [
       path('admin/', admin.site.urls),
       path('', home, name='home'),
       path('result/', result, name='result'),
       path('seth/', counters, name='seth'),
       #path('james/', post_details, name='james'),
       path('maggie/', maggie_post_details, name='maggie'),
       path('AllAbove/', all_above, name='AllAbove'),
       re_path(r'^posts/(?P<post_id>[0-9]+)/$', post_details, name='james'),
       path('simon/', redactors, name='simon'),
    ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
    Here is Alice and Wonderland in .txt format

    What other comments might you have about my code, in particular the views.py shared above?

    I’m running Django 2.2 and Python 3.7.

    Pull requests on GitHub (my repo can be found here) are welcome although I realize if asking for pull requests like this might not be reasonable for most of you but I thought I’d ask anyways, just in case a kind and generous forum contributor has time on their hands. Requirements.txt is included on the master branch.

    For what it is worth, here is some of the documentation I’ve been working with.

    I’ve referred to official Django docs for:

    Stack Overflow questions I’ve used:
    Last edited by Drone4four; 1 Week Ago at 03:16 PM. Reason: Replaced hyperlinks to GitHub with actual snippets of code + grammar + cosmetic changes
    My rig:
    IBM Personal System/2 Model 30-286 - - Intel 80286 (16 bit) 10 Mhz - - 1MB DRAM - - Integrated VGA Display adapter
    1.44MB capacity Floppy Disk - - PS/2 keyboard (no mouse)

  2. #2
    Join Date
    Jan 2017
    Beans
    80

    Re: TypeError: missing 1 required positional argument (word counter Django app)

    The following comments are from eyeballing the code that you have posted. It'll be tomorrow, if then, before I have time to download and run your app.

    The error is because you are calling counters() from url.py and it is expecting two parameters. If you want to call main you need to change this line:
    Code:
    path('seth/', counters, name='seth'),
    Don't know if there are any repercussions from calling main() but I believe it will need to return HttpResponse().

    The following returns to the caller after one iteration:
    Code:
        for word,count in top_10:
            return render(request, 'counters/seth.html', {'word': word, 'count': count})
    Try something like this:
    Code:
    #    for word,count in top_10:
         return render(request, 'counters/seth.html', {'top_10': top_10})
    Then in your template:
    Code:
    {% for word, count in top_10 %}
        {{word}} {{count}} <br>
    {% endfor %}

    Post back with any progress that you make. HTH

  3. #3
    Join Date
    May 2007
    Location
    Ontario
    Beans
    475
    Distro
    Ubuntu

    Re: TypeError: missing 1 required positional argument (word counter Django app)

    Thank you, @norobro! This helps.

    I managed to eliminate the TypeError and 'positional argument' issue. Alls I did was remove my silly global variable declarations and then change my function inside my views.py to look like this

    Code:
    def counters(request, text="")
    This eliminates the error that I discussed originally. No more trackback.

    But to achieve what I intend, you are right that I will need to include your three additional suggestions. I'll play around with these changes tomorrow. I'll report back here as soon as I can.

    Thanks for your help so far, @norobro.
    My rig:
    IBM Personal System/2 Model 30-286 - - Intel 80286 (16 bit) 10 Mhz - - 1MB DRAM - - Integrated VGA Display adapter
    1.44MB capacity Floppy Disk - - PS/2 keyboard (no mouse)

  4. #4
    Join Date
    May 2007
    Location
    Ontario
    Beans
    475
    Distro
    Ubuntu

    Re: TypeError: missing 1 required positional argument (word counter Django app)

    I’ve made a few changes based on your suggestions. Here are my latest changes in my GitHub repo. I talk through and discuss my changes below.

    Quote Originally Posted by norobro View Post
    The following returns to the caller after one iteration:

    Code:
        for word,count in top_10:
            return render(request, 'counters/seth.html', {'word': word, 'count': count})
    Try something like this:
    Code:
    #    for word,count in top_10:
         return render(request, 'counters/seth.html', {'top_10': top_10})
    I made this change. My counters function looks like this:

    Code:
    def counters(request, text=""):
       """
       This function processes the top 10 most common words and then renders them.
       """
       stoplist = stopwords.words('english')
       stoplist.extend(["said","gutenberg", "could", "would",])
       clean = []
       for word in re.split(r"\W+",text):
           if word not in stoplist:
               clean.append(word)
       top_10 = Counter(clean).most_common(10)
       # for word,count in top_10:
       return render(request, 'counters/seth.html', {'top_10': top_10})
    As you can see near the bottom there, the for loop has been commented out. Now this function just returns the request, the template location, and specifies the top_10 variable as a key-value pair.

    My template was rather basic. I hadn’t put much thought into it yet. So this was a great suggestion:

    Quote Originally Posted by norobro View Post
    Then in your template:
    Code:
    {% for word, count in top_10 %}
        {{ word }} {{ count }}  <br>
    {% endfor %}
    I agree that this makes a lot more sense for my ‘seth’ template. I transferred it over into my code.

    When I run the server, there are no errors in the shell. There’s no 404 or traceback either. When navigating to the ‘seth’ page, the output shows simply: “1”. See here:



    Then I went back and attempted to integrate your first suggestion by changing the function reference in urls.py. You suggested:
    Quote Originally Posted by norobro View Post
    The error is because you are calling counters() from url.py and it is expecting two parameters. If you want to call main you need to change this line:
    Code:
    path('seth/', counters, name='seth'),
    Don't know if there are any repercussions from calling main() but I believe it will need to return HttpResponse().
    So I changed the view function reference from ‘counters' to ‘main’ so that line looks like this now: path('seth/', main, name='seth').

    Now I am getting a NameError and TypeError depending on line 48 inside my view where I declare the text variable. Inside my main() function, I attempt to call the FileFieldView class and post method (which is present earlier above in this particular view). Here is my original line with the text declaration inside main:
    Code:
    text = FileFieldView.post(request)
    I tried these two as well (in addition to a few others):
    Code:
    text = FileFieldView(self).post(request, text)
    Code:
    text = FileFieldView(request).post(self, text)
    The shell raises: "NameError: name 'self' is not defined". I am struggling with grasping the basic concept of how to call instances of classes properly in this context.

    I’ve begun reviewing:
    Last edited by Drone4four; 1 Week Ago at 10:37 PM. Reason: Add shell raises
    My rig:
    IBM Personal System/2 Model 30-286 - - Intel 80286 (16 bit) 10 Mhz - - 1MB DRAM - - Integrated VGA Display adapter
    1.44MB capacity Floppy Disk - - PS/2 keyboard (no mouse)

  5. #5
    Join Date
    Jan 2017
    Beans
    80

    Re: TypeError: missing 1 required positional argument (word counter Django app)

    G'day Drone4four.

    Just for grins comment out the FileFieldView.post() call in main and add the following line to counters:
    Code:
        """
        This function processes the top 10 most common words and then renders them.
        """
        text = open("counters/Alice.txt", "r").read().lower()    # add this line
        stoplist = stopwords.words('english')
    I'm not clear about your ultimate goal. Are you planning to put the word count on a blog page? Or a separate page? What is the purpose of the FileFieldView class?

  6. #6
    Join Date
    May 2007
    Location
    Ontario
    Beans
    475
    Distro
    Ubuntu

    Re: TypeError: missing 1 required positional argument (word counter Django app)

    Quote Originally Posted by norobro View Post
    Just for grins comment out the FileFieldView.post() call in main and add the following line to counters:
    Code:
        """
        This function processes the top 10 most common words and then renders them.
        """
        text = open("counters/Alice.txt", "r").read().lower()    # add this line
        stoplist = stopwords.words('english')

    That worked, my friend!!



    Thank you for your help and guidance so far, @norobro.

    To answer your questions:

    TL;DR:
    I'm not clear about your ultimate goal. Are you planning to put the word count on a blog page? Or a separate page?
    In short, first on a separate page, then inside a blog post.

    What is the purpose of the FileFieldView class?
    As I explain below, the purpose of the FileFieldView class was to collect a file uploaded by the author of the blog. But this is just a stepping stone until I figure out how to re-direct the class method to analyze the content of the blog post instead of the uploaded text file.

    /end TL;DR.

    To elaborate in greater detail, in terms of the purpose and end-goal of my project, it’s intended to become a website which showcases three different learn-to-code opportunities:
    1. Process a fake credit card number entered by the user which then ‘redacts’ the first 12 of 16 digits of the input.
    2. Create a rudimentary blog. But my finished product will only show a single blog post. It’s not intended to show multiple posts. It’s not going to be used to publish posts regularly (like typical blogs are used for). There will be only one post.
    3. Wirte a word counter (inside an HTML table) embedded as part of the blog post.

    I’ve started out by writing these three features separately, in individual apps. Once all three run as intended, eventually I’ll assemble and consolidate all of them into a single template which will appear as the home/landing page of my website. This is my ultimate goal, to answer your question.

    I’ve completed the first two learning opportunities. To complete the third learning task, I’ve broken it down into three sub-objectives:
    1. Write a feature which processes a text file provided in the app’s source code directory. The output shows on an isolated, separate web page (for now). With your help, @norobro, this sub-task is now completed!
    2. Take that feature to the next step by processing a text file uploaded by the user (from the Django admin dashboard) for the blog post. I had intended on achieving this by using Django’s “FileFieldView” class. This is why I included the FileFieldView form. However after taking a closer look today at this File Uploads Django doc, since I don't need to upload multiple files, maybe all I need is a simple form containing the more basic “FileField” view leveraging the section of the Django doc titled “Handling uploaded files with a model
    3. Finally, I intend on rewiring this app to process or count the words in the contents of the one (and only) blog post and have the word counter embedded within that post
    Last edited by Drone4four; 1 Week Ago at 02:24 PM. Reason: grammar correction
    My rig:
    IBM Personal System/2 Model 30-286 - - Intel 80286 (16 bit) 10 Mhz - - 1MB DRAM - - Integrated VGA Display adapter
    1.44MB capacity Floppy Disk - - PS/2 keyboard (no mouse)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •