From 1d1ff53a21f90e2e7acac128d82653af932ed509 Mon Sep 17 00:00:00 2001 From: JasonGrace2282 Date: Thu, 2 May 2024 13:10:33 -0400 Subject: [PATCH] chore: fix common linting problems This also replaces f"{$1}" with str($1) to make the Alan formatting CI happy --- Ion.egg-info/PKG-INFO | 2 +- Ion.egg-info/SOURCES.txt | 4 +- README.rst | 2 +- SETUP.md | 12 ++-- config/docker/entrypoint.sh | 4 +- config/docker/initial_setup.sh | 6 +- config/scripts/README.md | 2 +- config/scripts/create_activities.py | 6 +- config/scripts/create_users.py | 2 +- docs/developing/eighth-models.rst | 2 +- docs/developing/requirements.rst | 12 ++-- intranet/apps/announcements/models.py | 2 +- intranet/apps/announcements/notifications.py | 18 +++--- intranet/apps/announcements/views.py | 4 +- intranet/apps/api/tests.py | 6 +- intranet/apps/auth/views.py | 6 +- .../bus/management/commands/import_routes.py | 4 +- intranet/apps/dashboard/views.py | 19 +++--- .../management/commands/delete_users.py | 4 +- .../management/commands/import_staff.py | 2 +- .../management/commands/import_students.py | 2 +- .../management/commands/year_cleanup.py | 8 +-- intranet/apps/dataimport/tests.py | 4 +- intranet/apps/eighth/Hybrid-README.rst | 10 ++-- .../apps/eighth/forms/admin/activities.py | 28 +++++---- intranet/apps/eighth/forms/admin/blocks.py | 4 +- .../management/commands/absence_email.py | 2 +- .../commands/delete_duplicate_signups.py | 2 +- .../management/commands/find_duplicates.py | 6 +- .../commands/generate_similarities.py | 4 +- .../commands/remove_withdrawn_students.py | 6 +- .../commands/signup_status_email.py | 14 ++--- .../management/commands/update_counselors.py | 4 +- intranet/apps/eighth/models.py | 52 ++++++++--------- intranet/apps/eighth/notifications.py | 6 +- intranet/apps/eighth/serializers.py | 6 +- intranet/apps/eighth/tasks.py | 22 ++++--- .../eighth/tests/admin/test_admin_general.py | 10 ++-- .../eighth/tests/admin/test_admin_groups.py | 20 +++---- intranet/apps/eighth/tests/test_activities.py | 4 +- intranet/apps/eighth/tests/test_attendance.py | 4 +- intranet/apps/eighth/tests/test_exceptions.py | 2 +- intranet/apps/eighth/views/activities.py | 6 +- .../apps/eighth/views/admin/activities.py | 10 ++-- .../apps/eighth/views/admin/attendance.py | 20 +++---- intranet/apps/eighth/views/admin/blocks.py | 24 ++++---- intranet/apps/eighth/views/admin/groups.py | 42 +++++++------- intranet/apps/eighth/views/admin/hybrid.py | 16 +++--- .../apps/eighth/views/admin/maintenance.py | 2 +- intranet/apps/eighth/views/admin/rooms.py | 2 +- .../apps/eighth/views/admin/scheduling.py | 20 +++---- intranet/apps/eighth/views/admin/sponsors.py | 2 +- intranet/apps/eighth/views/attendance.py | 36 ++++++------ intranet/apps/eighth/views/monitoring.py | 2 +- intranet/apps/eighth/views/signup.py | 36 ++++++------ intranet/apps/emailfwd/models.py | 2 +- intranet/apps/emailfwd/views.py | 7 +-- intranet/apps/emerg/views.py | 6 +- intranet/apps/enrichment/models.py | 2 +- intranet/apps/events/models.py | 6 +- intranet/apps/events/notifications.py | 2 +- intranet/apps/events/tests.py | 8 +-- intranet/apps/events/views.py | 4 +- intranet/apps/feedback/models.py | 2 +- intranet/apps/feedback/views.py | 8 +-- intranet/apps/files/forms.py | 4 +- intranet/apps/files/models.py | 2 +- intranet/apps/files/views.py | 50 ++++++++-------- intranet/apps/groups/models.py | 2 +- intranet/apps/itemreg/models.py | 10 ++-- .../itemreg/templatetags/texthighlight.py | 2 +- intranet/apps/itemreg/views.py | 6 +- intranet/apps/logs/models.py | 2 +- intranet/apps/logs/views.py | 2 +- intranet/apps/lostfound/models.py | 4 +- intranet/apps/notifications/emails.py | 4 +- intranet/apps/notifications/models.py | 4 +- intranet/apps/notifications/views.py | 4 +- intranet/apps/oauth/admin.py | 4 +- intranet/apps/parking/admin.py | 4 +- intranet/apps/parking/models.py | 6 +- intranet/apps/parking/views.py | 14 ++--- intranet/apps/polls/models.py | 16 +++--- intranet/apps/preferences/tests.py | 4 +- intranet/apps/preferences/views.py | 8 +-- intranet/apps/printing/forms.py | 4 +- intranet/apps/printing/magic_files/msooxml | 4 +- intranet/apps/printing/models.py | 2 +- intranet/apps/printing/views.py | 46 +++++++-------- intranet/apps/schedule/api.py | 2 +- intranet/apps/schedule/models.py | 12 ++-- intranet/apps/schedule/notifications.py | 4 +- intranet/apps/schedule/views.py | 10 ++-- intranet/apps/search/utils.py | 2 +- intranet/apps/search/views.py | 54 +++++++++--------- .../management/commands/import_colleges.py | 4 +- intranet/apps/seniors/models.py | 4 +- intranet/apps/seniors/tests.py | 2 +- intranet/apps/seniors/views.py | 7 +-- intranet/apps/signage/consumers.py | 2 +- intranet/apps/signage/pages.py | 2 +- intranet/apps/signage/templatetags/signage.py | 2 +- intranet/apps/signage/views.py | 2 +- intranet/apps/templatetags/dates.py | 8 +-- intranet/apps/templatetags/forms.py | 2 +- intranet/apps/users/api.py | 3 +- intranet/apps/users/forms.py | 2 +- .../management/commands/import_groups.py | 10 ++-- intranet/apps/users/models.py | 13 ++--- intranet/apps/users/tests.py | 23 ++++---- intranet/apps/users/views.py | 6 +- intranet/settings/__init__.py | 2 +- .../{confectionary.png => confectionery.png} | Bin .../{confectionary.png => confectionery.png} | Bin scripts/dev_autoupdate_static.sh | 2 +- 115 files changed, 480 insertions(+), 512 deletions(-) rename intranet/static/img/patterns/{confectionary.png => confectionery.png} (100%) rename intranet/static/img/patterns/dark/{confectionary.png => confectionery.png} (100%) diff --git a/Ion.egg-info/PKG-INFO b/Ion.egg-info/PKG-INFO index cbc1350b409..f540efe953c 100644 --- a/Ion.egg-info/PKG-INFO +++ b/Ion.egg-info/PKG-INFO @@ -92,7 +92,7 @@ Intranet 3 *Version 3.0.0* -Intranet3 (Ion) is the next-generation Intranet platform for `TJHSST +Intranet3 (Ion) is the next-generation Intranet platform for `TJHSST `_. Using Python, Django, Redis, Postgres, and many other technologies, Ion was developed from the ground up to be simple, well-documented, and extensible. Documentation (in RestructuredText format) is available inside the "docs" folder or at https://tjcsl.github.io/ion publicly on the web. diff --git a/Ion.egg-info/SOURCES.txt b/Ion.egg-info/SOURCES.txt index 35256dafc97..3112c26638b 100644 --- a/Ion.egg-info/SOURCES.txt +++ b/Ion.egg-info/SOURCES.txt @@ -1024,7 +1024,7 @@ intranet/static/img/logos/touch/touch-icon76.png intranet/static/img/patterns/brushed.png intranet/static/img/patterns/brushed_@2X.png intranet/static/img/patterns/concrete_seamless.png -intranet/static/img/patterns/confectionary.png +intranet/static/img/patterns/confectionery.png intranet/static/img/patterns/contemporary_china.png intranet/static/img/patterns/contemporary_china_2.png intranet/static/img/patterns/cream_pixels.png @@ -1051,7 +1051,7 @@ intranet/static/img/patterns/squared_metal_@2X.png intranet/static/img/patterns/dark/brushed.png intranet/static/img/patterns/dark/brushed_@2X.png intranet/static/img/patterns/dark/concrete_seamless.png -intranet/static/img/patterns/dark/confectionary.png +intranet/static/img/patterns/dark/confectionery.png intranet/static/img/patterns/dark/contemporary_china.png intranet/static/img/patterns/dark/contemporary_china_2.png intranet/static/img/patterns/dark/cream_pixels.png diff --git a/README.rst b/README.rst index 17d773bca29..f868b6130e1 100644 --- a/README.rst +++ b/README.rst @@ -11,7 +11,7 @@ Intranet 3 *Version 3.0.0* -Intranet3 (Ion) is the next-generation Intranet platform for `TJHSST +Intranet3 (Ion) is the next-generation Intranet platform for `TJHSST `_. Using Python, Django, Redis, Postgres, and many other technologies, Ion was developed from the ground up to be simple, well-documented, and extensible. Documentation (in RestructuredText format) is available inside the "docs" folder or at https://tjcsl.github.io/ion publicly on the web. diff --git a/SETUP.md b/SETUP.md index e1d69bf3089..57a646507a4 100644 --- a/SETUP.md +++ b/SETUP.md @@ -14,7 +14,7 @@ The Git repository on the host computer is synced with ``~/intranet`` on the vir ## Set Up 1. Create your own fork of the [``tjcsl/ion`` repository](https://github.com/tjcsl/ion.git). -2. Clone the Ion repositiory from your Ion fork by running ``git clone git@github.com:/ion.git intranet``. Note: if your host machine is running Windows, please run ``git config core.autocrlf input`` before cloning to prevent line ending issues. +2. Clone the Ion repository from your Ion fork by running ``git clone git@github.com:/ion.git intranet``. Note: if your host machine is running Windows, please run ``git config core.autocrlf input`` before cloning to prevent line ending issues. 3. Run ``cd config/docker`` 4. Run `docker compose build ` (or use `docker-compose build` if this doesn't work) 5. Run ``docker compose up`` @@ -35,7 +35,7 @@ Navigate to http://localhost:8080 in the web browser of your choice. You might h ### Interacting with the application: -If you need to run a Django command like ``makemigrations``, ``collectstatic`` or ``shell_plus``, run ``docker exec -it intranet bash`` in your terminal. That wlll give you a shell into the application container. You can also use this to run scripts like ``build_sources.sh``. If you need to view the output from or restart ``runserver``, run ``docker attach application``. +If you need to run a Django command like ``makemigrations``, ``collectstatic`` or ``shell_plus``, run ``docker exec -it intranet bash`` in your terminal. That will give you a shell into the application container. You can also use this to run scripts like ``build_sources.sh``. If you need to view the output from or restart ``runserver``, run ``docker attach application``. ### Attaching to logs @@ -45,14 +45,14 @@ To view logs of a container, run `docker logs [CONTAINER NAME] -f`. For example, ## Prerequisites -- [Virtualbox](https://www.virtualbox.org/) is a virtualization service that allows the creation of virtual machines. Installation is OS-specific and instructions can be found [here](https://www.virtualbox.org/wiki/Downloads). +- [Virtualbox](https://www.virtualbox.org/) is a virtualization service that allows the creation of virtual machines. Installation is OS-specific and instructions can be found [here](https://www.virtualbox.org/wiki/Downloads). - [Vagrant](https://www.vagrantup.com/) is a command line utility for managing and setting up virtual machines and environments. Installation is OS-specific and instructions can be found [here](https://developer.hashicorp.com/vagrant/downloads). - [GitHub](https://github.com) is the version control system used by the CSL. Make sure that you have an account and an SSH key tied to that account that will allow you to push and pull code. Ensure you have an SSH key set up with GitHub by running ``ssh -T git@github.com``. You should be greeted by your username. If not, set up an SSH key with GitHub by following [these instructions](https://help.github.com/articles/generating-an-ssh-key/). ## Set Up 1. Create your own fork of the [``tjcsl/ion`` repository](https://github.com/tjcsl/ion.git). -2. Clone the Ion repositiory from your Ion fork by running ``git clone git@github.com:/ion.git intranet``. Note: if your host machine is running Windows, please run ``git config core.autocrlf input`` before cloning to prevent line ending issues. +2. Clone the Ion repository from your Ion fork by running ``git clone git@github.com:/ion.git intranet``. Note: if your host machine is running Windows, please run ``git config core.autocrlf input`` before cloning to prevent line ending issues. 3. In the ``config/vagrant`` directory, copy the file ``devconfig.json.sample`` to ``devconfig.json`` and edit the properties in ``devconfig.json`` as appropriate. Ensure ``ssh_key`` is set to the same SSH key registered with GitHub (e.g. ``id_rsa``). 4. Run ``vagrant plugin install vagrant-vbguest``. If you are on Windows, also run ``vagrant plugin install vagrant-winnfsd``. 5. Run ``vagrant up && vagrant reload`` and wait while the development environment is set up. If you are asked to select a network interface for bridging, enter the number corresponding to one that is active. To automatically select this interface in the future, set the "network_interface" key in ``devconfig.json`` to the name of the interface you selected (e.g. ``"en0: Wi-Fi (AirPort)"``). There may be repeated warnings similar to "``Remote connection disconnect`` and ``Warning: Connection aborted. Retrying...`` on the second ``vagrant up``. After several minutes they will stop. @@ -100,11 +100,11 @@ When you want to close the VM environment, make sure you have exited out of the ## Changing Master Password -The master password for vagrant development enviornment is ``swordfish``. +The master password for vagrant development environment is ``swordfish``. In non-Vagrant environments, you should set a master password different from the default. Ideally, this password should have many bits of entropy and should be randomly generated. -We use the secure Argon2 hashing algorithim to secure our master password. To set the master password, set ``MASTER_PASSWORD`` to the string output of the below script (after changing values as appropriate) in ``secret.py``. After changing this value, restart Ion. +We use the secure Argon2 hashing algorithm to secure our master password. To set the master password, set ``MASTER_PASSWORD`` to the string output of the below script (after changing values as appropriate) in ``secret.py``. After changing this value, restart Ion. Currently, Ion requires that you use Argon2id to create the hash. You also must prepend ``argon2`` to the hash before putting it into ``secret.py``. diff --git a/config/docker/entrypoint.sh b/config/docker/entrypoint.sh index f231c482f96..fdbd9257296 100755 --- a/config/docker/entrypoint.sh +++ b/config/docker/entrypoint.sh @@ -1,6 +1,6 @@ #!/bin/sh -if [ ! -f "config/docker/first-run.log" ]; then +if [ ! -f "config/docker/first-run.log" ]; then echo "# Log of first run, to run initial setup again, delete this file" > config/docker/first-run.log /bin/sh config/docker/initial_setup.sh 2>&1 | tee -a config/docker/first-run.log fi @@ -11,7 +11,7 @@ export PYTHONUNBUFFERED=1 # Don't buffer Django output # Wrap the run command in a loop so that it restarts if it crashes, e.g. due to a syntax error while true -do +do python3 manage.py run 0.0.0.0:8080 # Custom run command that skips system checks for performance sleep 1 done diff --git a/config/docker/initial_setup.sh b/config/docker/initial_setup.sh index 214d028c217..3786433fc8b 100755 --- a/config/docker/initial_setup.sh +++ b/config/docker/initial_setup.sh @@ -9,10 +9,10 @@ echo -e "${BLUE}${BOLD}Copying over secret.py...${CLEAR}" cp -u config/docker/secret.py intranet/settings echo -e "${BLUE}${BOLD}Collecting static...${CLEAR}" -python3 manage.py collectstatic --noinput +python3 manage.py collectstatic --noinput echo -e "${BLUE}${BOLD}Running migrations...${CLEAR}" -python3 manage.py migrate +python3 manage.py migrate echo -e "${BLUE}${BOLD}Copying over scripts...${CLEAR}" cp config/scripts/*.py . @@ -22,7 +22,7 @@ for year in "freshman" "sophomore" "junior" "senior"; do python3 create_users.py -t student -nw -y $year -n student student1 student2 student3 student4 student5 python3 create_users.py -t admin -nw -y $year -n admin admin1 admin2 admin3 admin4 admin5 done -python3 create_users.py -nw -ny -t admin -n admin +python3 create_users.py -nw -ny -t admin -n admin python3 create_users.py -t admin -c 10 python3 create_users.py -t student -c 100 python3 create_users.py -t teacher -c 20 diff --git a/config/scripts/README.md b/config/scripts/README.md index 121400bb137..6ac5d9ae413 100644 --- a/config/scripts/README.md +++ b/config/scripts/README.md @@ -8,7 +8,7 @@ A set of scripts to generate somewhat realistic student data for the Ion develop - To run manually and/or change data: - Delete `config/docker/first-run.log` - + - Then, either: - Restart the container to load new data - Or manually run `config/docker/initial_setup.sh` diff --git a/config/scripts/create_activities.py b/config/scripts/create_activities.py index ab24e5b5281..0ee5f244e74 100644 --- a/config/scripts/create_activities.py +++ b/config/scripts/create_activities.py @@ -33,9 +33,9 @@ def generate_activities(args: argparse.Namespace) -> None: if restriction == "senior": activity.seniors_allowed = True - sponser = EighthSponsor.objects.get_or_create(user=random.choice(teachers))[0] - sponser.save() - activity.sponsors.set((sponser,)) + sponsor = EighthSponsor.objects.get_or_create(user=random.choice(teachers))[0] + sponsor.save() + activity.sponsors.set((sponsor,)) room = EighthRoom.objects.get_or_create(name=f"Room {random.randint(1, 100)}")[0] room.save() diff --git a/config/scripts/create_users.py b/config/scripts/create_users.py index 1fd2b53f7d5..78c85baa93f 100644 --- a/config/scripts/create_users.py +++ b/config/scripts/create_users.py @@ -112,7 +112,7 @@ def generate_names(args: argparse.Namespace) -> "list[tuple[str]]": def main() -> None: parser = argparse.ArgumentParser() parser.add_argument( - "-n", "--names", nargs="+", default=[], help="Provide in format first_last, or as a username, ignores count if supplied, seperate with '_'" + "-n", "--names", nargs="+", default=[], help="Provide in format first_last, or as a username, ignores count if supplied, separate with '_'" ) parser.add_argument("-c", "--count", type=int, default=10, help="Number of users to make, defaults to 10") parser.add_argument("-t", "--type", type=str, required=True, choices=["student", "teacher", "admin"], help="type of user to make") diff --git a/docs/developing/eighth-models.rst b/docs/developing/eighth-models.rst index 8b7657a1881..9fac7764dd4 100644 --- a/docs/developing/eighth-models.rst +++ b/docs/developing/eighth-models.rst @@ -21,7 +21,7 @@ What follows is a brief list of the eighth models with a description of each. Mo The ``add_user()`` method of this class is where all of the logic to sign a user up for an activity is. Be *very* careful when modifying it. - ``EighthSignup``: Represents that a user is signed up for a particular ``EighthScheduledActivity`` during the block for which it is scheduled. Has ``ForeignKey``\s to the ``EighthScheduledActivity`` and the ``User`` objects. Also stores some information such as whether the user signed up after the deadline (assumed to be a pass), whether the user signed themselves up or was signed up by an eighth admin, the name and sponsor list of the activity they were signed up for previously (if applicable), whether they were absent, etc. - + **Note**: Since Ion's launch, it has been plagued by duplicate ``EighthSignup``\s (``EighthSignup``\s for the same user during the same block) being created. There are multiple checks before the object is saved to make sure it is unique, and uniqueness is enforced on a per-user, per- ``EighthScheduledActivity`` basis at the model level, but the problem has continued. As of summer 2019, measures have been enacted that will hopefully minimize the occurrences of this issue in the future, as well as allow better diagnosing of the problem if it occurs again. - ``EighthWaitlist``: Ion has all of the backend logic to implement waitlists for each activity, but it is not enabled in production (``settings.ENABLE_WAITLIST`` is ``False``). When the waitlist is enabled, an ``EighthWaitlist`` object represents that a user signed up for the waitlist for a particular ``EighthScheduledActivity`` at a particular time. The user's position in the waitlist is calculated dynamically by finding the number of users who signed up for the waitlist before them. diff --git a/docs/developing/requirements.rst b/docs/developing/requirements.rst index 7bb0e46c5c3..3b834ba694e 100644 --- a/docs/developing/requirements.rst +++ b/docs/developing/requirements.rst @@ -21,7 +21,7 @@ autobahn ----------------- https://github.com/crossbario/autobahn-python -This package provides `WebSocket _` & `Web Appplication Messaging Protocol (WAMP) _` support. +This package provides `WebSocket _` & `Web Application Messaging Protocol (WAMP) _` support. It provides WebSocket support for Ion. @@ -141,7 +141,7 @@ django ------------------ https://github.com/django/django -Django is a high-level Python Web framework that encourages rapid development and clean, pragmatic design. +Django is a high-level Python Web framework that encourages rapid development and clean, pragmatic design. It is used as our web framework. @@ -153,7 +153,7 @@ https://github.com/Suor/django-cacheops This package is a Django app that supports automatic or manual queryset caching into a Redis ORM cache. -It is used for queryset caching into a Redis databse. +It is used for queryset caching into a Redis database. LICENSE: 3-clause BSD @@ -259,7 +259,7 @@ django-redis-cache --------------------- https://github.com/sebleier/django-redis-cache -This package provides the redis backend cache. +This package provides the redis backend cache. FIXME: Needs more specific info @@ -323,7 +323,7 @@ docutils --------- https://sourceforge.net/p/docutils/code/HEAD/tree/trunk/docutils/ -This package provides a modular system for processing documentation into useful formats, such as HTML, XML, and LaTeX. +This package provides a modular system for processing documentation into useful formats, such as HTML, XML, and LaTeX. It is an optional dependency for admindocs and setuptools. @@ -333,7 +333,7 @@ https://github.com/mathiasertl/fabric/ This package provides a basic suite of operations for executing local or remote shell commands (normally or via sudo) and uploading/downloading files, as well as auxiliary functionality such as prompting the running user for input, or aborting execution. -It is used to manage the Ion application in both developement and production (see ``fabfile.py``) +It is used to manage the Ion application in both development and production (see ``fabfile.py``) NEEDSRELEASE diff --git a/intranet/apps/announcements/models.py b/intranet/apps/announcements/models.py index b8d445aecea..96fe49471c9 100644 --- a/intranet/apps/announcements/models.py +++ b/intranet/apps/announcements/models.py @@ -77,7 +77,7 @@ class AnnouncementUserMap(models.Model): users_seen = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, related_name="announcements_seen") def __str__(self): - return "UserMap: {}".format(self.announcement.title) + return f"UserMap: {self.announcement.title}" class Announcement(models.Model): diff --git a/intranet/apps/announcements/notifications.py b/intranet/apps/announcements/notifications.py index e2e61ecabf9..3e8ab893f2f 100644 --- a/intranet/apps/announcements/notifications.py +++ b/intranet/apps/announcements/notifications.py @@ -31,7 +31,7 @@ def request_announcement_email(request, form, obj): teacher_ids = [teacher_ids] teachers = get_user_model().objects.filter(id__in=teacher_ids) - subject = "News Post Confirmation Request from {}".format(request.user.full_name) + subject = f"News Post Confirmation Request from {request.user.full_name}" emails = [] for teacher in teachers: emails.append(teacher.tj_email) @@ -56,7 +56,7 @@ def admin_request_announcement_email(request, form, obj): """ - subject = "News Post Approval Needed ({})".format(obj.title) + subject = f"News Post Approval Needed ({obj.title})" emails = [settings.APPROVAL_EMAIL] base_url = request.build_absolute_uri(reverse("index")) data = { @@ -80,7 +80,7 @@ def announcement_approved_email(request, obj, req): if not settings.PRODUCTION: logger.debug("Not in production. Ignoring email for approved announcement.") return - subject = "Announcement Approved: {}".format(obj.title) + subject = f"Announcement Approved: {obj.title}" """ Email to teachers who approved. """ teachers = req.teachers_approved.all() @@ -94,7 +94,7 @@ def announcement_approved_email(request, obj, req): email_send_task.delay( "announcements/emails/announcement_approved.txt", "announcements/emails/announcement_approved.html", data, subject, teacher_emails ) - messages.success(request, "Sent teacher approved email to {} users".format(len(teacher_emails))) + messages.success(request, f"Sent teacher approved email to {len(teacher_emails)} users") """ Email to submitter. """ submitter = req.user data = {"announcement": obj, "request": req, "info_link": url, "base_url": base_url, "role": "submitted"} @@ -112,7 +112,7 @@ def announcement_posted_email(request, obj, send_all=False): """ if settings.EMAIL_ANNOUNCEMENTS: - subject = "Announcement: {}".format(obj.title) + subject = f"Announcement: {obj.title}" if send_all: users = ( get_user_model() @@ -145,7 +145,7 @@ def announcement_posted_email(request, obj, send_all=False): email_send_task.delay( "announcements/emails/announcement_posted.txt", "announcements/emails/announcement_posted.html", data, subject, emails, bcc=True ) - messages.success(request, "Sent email to {} users".format(len(users_send))) + messages.success(request, f"Sent email to {len(users_send)} users") else: logger.info("Emailing announcements disabled") @@ -159,9 +159,9 @@ def announcement_posted_twitter(request, obj): content = re.sub("<[^>]*>", "", obj.content) content = content.replace(" ", " ") content_len = 139 - (len(title) + 2 + 3 + 3 + 22) - text = "{}: {}... - {}".format(title, content[:content_len], url) + text = f"{title}: {content[:content_len]}... - {url}" else: - text = "{}... - {}".format(title[:110], url) + text = f"{title[:110]}... - {url}" logger.info("Posting tweet: %s", text) try: @@ -174,7 +174,7 @@ def announcement_posted_twitter(request, obj): capture_exception(e) else: if respobj and "id" in respobj: - messages.success(request, "Posted tweet: {}".format(text)) + messages.success(request, f"Posted tweet: {text}") messages.success(request, "https://twitter.com/tjintranet/status/{}".format(respobj["id"])) else: messages.error(request, resp) diff --git a/intranet/apps/announcements/views.py b/intranet/apps/announcements/views.py index a9e85b17e39..b0c83c97eb1 100644 --- a/intranet/apps/announcements/views.py +++ b/intranet/apps/announcements/views.py @@ -55,7 +55,7 @@ def announcement_posted_hook(request, obj): announcement_posted_email(request, obj) except Exception as e: logger.error("Exception when emailing announcement: %s", e) - messages.error(request, "Exception when emailing announcement: {}".format(e)) + messages.error(request, f"Exception when emailing announcement: {e}") raise e else: logger.debug("Announcement notify off") @@ -308,7 +308,7 @@ def modify_announcement_view(request, announcement_id=None): form = AnnouncementEditForm(request.POST, instance=announcement) if form.is_valid(): obj = form.save() - if "update_added_date" in form.cleaned_data and form.cleaned_data["update_added_date"]: + if form.cleaned_data.get("update_added_date"): obj.added = timezone.now() if form.cleaned_data.get("notify_post_resend") or form.cleaned_data.get("notify_email_all_resend"): obj.notify_post = form.cleaned_data["notify_post_resend"] diff --git a/intranet/apps/api/tests.py b/intranet/apps/api/tests.py index 73051c0e417..84089ce95e5 100644 --- a/intranet/apps/api/tests.py +++ b/intranet/apps/api/tests.py @@ -49,7 +49,7 @@ def make_token(self): tok = AccessToken.objects.create( user=self.user, token="1234567890", application=self.application, scope="read write", expires=timezone.now() + datetime.timedelta(days=1) ) - self.auth = "Bearer {}".format(tok.token) + self.auth = f"Bearer {tok.token}" def get_api_eighth_block_list(self, query=""): return self.client.get(reverse("api_eighth_block_list") + query, HTTP_AUTHORIZATION=self.auth) @@ -115,7 +115,7 @@ def test_oauth_client_credentials_read(self): scope="read write", expires=timezone.now() + datetime.timedelta(days=1), ) - auth = "Bearer {}".format(tok.token) + auth = f"Bearer {tok.token}" # List announcements response = self.client.get(reverse("api_announcements_list_create"), HTTP_AUTHORIZATION=auth) @@ -156,7 +156,7 @@ def test_oauth_client_credentials_read_anonymous(self): scope="read write", expires=timezone.now() + datetime.timedelta(days=1), ) - auth = "Bearer {}".format(tok.token) + auth = f"Bearer {tok.token}" # List announcements response = self.client.get(reverse("api_announcements_list_create"), HTTP_AUTHORIZATION=auth) diff --git a/intranet/apps/auth/views.py b/intranet/apps/auth/views.py index d10e5ad4882..0adc9d79625 100644 --- a/intranet/apps/auth/views.py +++ b/intranet/apps/auth/views.py @@ -29,8 +29,8 @@ from ..events.models import Event from ..schedule.views import schedule_context from ..sessionmgmt.helpers import trust_session -from . import backends # pylint: disable=unused-import # noqa # Load it so the Prometheus metrics get added -from . import signals # pylint: disable=unused-import # noqa # Load it so the signals get registered +# Load these so the Prometheus metrics get added +from . import backends, signals # pylint: disable=unused-import # noqa F401 from .forms import AuthenticateForm from .helpers import change_password @@ -65,7 +65,7 @@ def get_bg_pattern(request): files = [ "brushed.png", "concrete_seamless.png", - "confectionary.png", + "confectionery.png", "contemporary_china.png", "crossword.png", # "fresh_snow.png", diff --git a/intranet/apps/bus/management/commands/import_routes.py b/intranet/apps/bus/management/commands/import_routes.py index 5fad4199280..e7885445dbe 100644 --- a/intranet/apps/bus/management/commands/import_routes.py +++ b/intranet/apps/bus/management/commands/import_routes.py @@ -9,13 +9,13 @@ class Command(BaseCommand): help = "Import Routes from routes.csv" def handle(self, *args, **options): - with open("routes.csv", "r", encoding="utf-8") as f: + with open("routes.csv", encoding="utf-8") as f: reader = csv.reader(f) print("Deleting preexisting buses") for row in reader: (name,) = row _, created = Route.objects.get_or_create(route_name=name) if created: - print("Created route {}".format(name)) + print(f"Created route {name}") else: print("Route {} already exists") diff --git a/intranet/apps/dashboard/views.py b/intranet/apps/dashboard/views.py index 1f0e455cf11..b2400653b8f 100644 --- a/intranet/apps/dashboard/views.py +++ b/intranet/apps/dashboard/views.py @@ -231,12 +231,10 @@ def get_announcements_list(request, context): # Show all announcements if user has admin permissions and the # show_all GET argument is given. announcements = Announcement.objects.all() + elif context["show_expired"]: + announcements = Announcement.objects.visible_to_user(user) else: - # Only show announcements for groups that the user is enrolled in. - if context["show_expired"]: - announcements = Announcement.objects.visible_to_user(user) - else: - announcements = Announcement.objects.visible_to_user(user).filter(expiration_date__gt=timezone.now()) + announcements = Announcement.objects.visible_to_user(user).filter(expiration_date__gt=timezone.now()) # Load information on the user who posted the announcement # Unless the announcement has a custom author (some do, but not all), we will need the user information to construct the byline, @@ -248,13 +246,12 @@ def get_announcements_list(request, context): if context["events_admin"] and context["show_all"]: events = Event.objects.all() + elif context["show_expired"]: + events = Event.objects.visible_to_user(user) else: - if context["show_expired"]: - events = Event.objects.visible_to_user(user) - else: - # Unlike announcements, show events for the rest of the day after they occur. - midnight = timezone.localtime().replace(hour=0, minute=0, second=0, microsecond=0) - events = Event.objects.visible_to_user(user).filter(time__gte=midnight, show_on_dashboard=True) + # Unlike announcements, show events for the rest of the day after they occur. + midnight = timezone.localtime().replace(hour=0, minute=0, second=0, microsecond=0) + events = Event.objects.visible_to_user(user).filter(time__gte=midnight, show_on_dashboard=True) def announcements_sorting_key(item): if context["show_expired"] or context["show_all"]: diff --git a/intranet/apps/dataimport/management/commands/delete_users.py b/intranet/apps/dataimport/management/commands/delete_users.py index 7f92f17c724..4aa13f7acdf 100644 --- a/intranet/apps/dataimport/management/commands/delete_users.py +++ b/intranet/apps/dataimport/management/commands/delete_users.py @@ -24,7 +24,7 @@ def add_arguments(self, parser): parser.add_argument("--confirm", action="store_true", dest="confirm", default=False, help="Skip confirmation.") def ask(self, q): - if input("{} [Yy]: ".format(q)).lower() != "y": + if input(f"{q} [Yy]: ").lower() != "y": self.stdout.write(self.style.ERROR("Abort.")) sys.exit() @@ -40,7 +40,7 @@ def read_student_ids(self, filename: str, column_header: str): """ ids = [] - with open(filename, "r", encoding="utf-8") as csvfile: + with open(filename, encoding="utf-8") as csvfile: reader = csv.DictReader(csvfile) for row in reader: ids.append(row[column_header]) diff --git a/intranet/apps/dataimport/management/commands/import_staff.py b/intranet/apps/dataimport/management/commands/import_staff.py index 45f0f0212a7..85260f9c61e 100644 --- a/intranet/apps/dataimport/management/commands/import_staff.py +++ b/intranet/apps/dataimport/management/commands/import_staff.py @@ -25,7 +25,7 @@ def ask(self, q): def handle(self, *args, **options): # Read the data file - with open(options["filename"], "r", encoding="utf-8") as csvfile: + with open(options["filename"], encoding="utf-8") as csvfile: data = list(csv.DictReader(csvfile)) do_run = options["run"] diff --git a/intranet/apps/dataimport/management/commands/import_students.py b/intranet/apps/dataimport/management/commands/import_students.py index 98461b82710..45c37ce2b5e 100644 --- a/intranet/apps/dataimport/management/commands/import_students.py +++ b/intranet/apps/dataimport/management/commands/import_students.py @@ -81,7 +81,7 @@ def increment_username(username: str): def handle(self, *args, **options): # Read the data file - with open(options["filename"], "r", encoding="utf-8") as csvfile: + with open(options["filename"], encoding="utf-8") as csvfile: data = list(csv.DictReader(csvfile)) do_run = options["run"] diff --git a/intranet/apps/dataimport/management/commands/year_cleanup.py b/intranet/apps/dataimport/management/commands/year_cleanup.py index 6c496b1e365..86892f4a1ba 100644 --- a/intranet/apps/dataimport/management/commands/year_cleanup.py +++ b/intranet/apps/dataimport/management/commands/year_cleanup.py @@ -24,7 +24,7 @@ def add_arguments(self, parser): ) def ask(self, q): - if input("{} [Yy]: ".format(q)).lower() != "y": + if input(f"{q} [Yy]: ").lower() != "y": self.stdout.write("Abort.") sys.exit() @@ -58,7 +58,7 @@ def handle(self, *args, **options): senior_grad_year = options["senior_grad_year"] - if not self.chk("senior_grad_year = {}".format(new_senior_year), senior_grad_year == new_senior_year): + if not self.chk(f"senior_grad_year = {new_senior_year}", senior_grad_year == new_senior_year): return """ EIGHTH: @@ -91,7 +91,7 @@ def handle(self, *args, **options): def clear_absences(self): absents = EighthSignup.objects.filter(was_absent=True) - self.stdout.write("{} absent eighth signups".format(absents.count())) + self.stdout.write(f"{absents.count()} absent eighth signups") for a in absents: a.archive_remove_absence() self.stdout.write("Archived absences") @@ -111,4 +111,4 @@ def handle_delete(self, *, senior_grad_year: int): else: usr.user_type = "alum" usr.save() - self.stdout.write("User {} KEEP".format(usr.username)) + self.stdout.write(f"User {usr.username} KEEP") diff --git a/intranet/apps/dataimport/tests.py b/intranet/apps/dataimport/tests.py index ff9e934f07b..9a79b1a6bc8 100755 --- a/intranet/apps/dataimport/tests.py +++ b/intranet/apps/dataimport/tests.py @@ -24,7 +24,7 @@ def test_year_cleanup(self): output = [ "In pretend mode.", "Turnover date set to: {}".format(turnover_date.strftime("%c")), - "OK: senior_grad_year = {}".format(year + 1), + f"OK: senior_grad_year = {year + 1}", "Resolving absences", "Updating welcome state", "Deleting graduated users", @@ -106,7 +106,7 @@ def test_delete_users(self): with patch("intranet.apps.dataimport.management.commands.delete_users.open", mock_open(read_data=file_contents)) as m: call_command("delete_users", filename="foo.csv", header="Student ID", run=True, confirm=True) - m.assert_called_with("foo.csv", "r", encoding="utf-8") + m.assert_called_with("foo.csv", encoding="utf-8") with self.assertRaises(get_user_model().DoesNotExist): get_user_model().objects.get(username="2021ttester") diff --git a/intranet/apps/eighth/Hybrid-README.rst b/intranet/apps/eighth/Hybrid-README.rst index 228afdde0a2..74f74e8eed9 100644 --- a/intranet/apps/eighth/Hybrid-README.rst +++ b/intranet/apps/eighth/Hybrid-README.rst @@ -6,7 +6,7 @@ The purpose of this document is to help whoever has to revert these changes that The motivation behind these changes was: 1) Avoid putting any extra burden on the 8PO -2) Keep these changes as seperate as possible so that they can be reverted +2) Keep these changes as separate as possible so that they can be reverted 3) Not break ``eighth`` First, this document assumes that all students have been sorted into four groups named ``virtual``, ``in-person (a-k)``, ``in-person (l-z)`` and ``in-person``, that these groups are always correct and that each student is in only one group. It is on 8PO and/or the main office to ensure that these groups are accurate, not us. These groups NEED to be created for the code to work with ENABLE_HYBRID_EIGHTH set to True. @@ -28,14 +28,14 @@ Blocks *********** * In ``intranet/templates/eighth/admin/add_blocks.html``, a checkbox is added to give 8PO control over if groups are automatically stickied into the appropriate blocks or not. -* In ``intranet/apps/eighth/views/admin/blocks.py``, everything that has been changed is placed between two lines of comments and is behind an if statement checking if the ``ENABLE_HYBRID_EIGHTH`` setting is ``True``. In ``edit_block_view``, a simple warning is given that changing a block name will not change the students that are stickied for that block. Trying to to this here just creates conflicts. 8PO is encouraged to just delete the block and create a new one. In ``add_block_view``, different ``visable_blocks`` are shown and additional context is added. If the "assign_hybrid" checkbox is checked, the appropriate groups will be sticked into the correct admin acitivity according to comments provided throughout and the naming conventions above. As a note, ``attendance_taken`` is set to true, although ``was_absent`` in ``EighthSignup`` is left blank. This is so that 8PO doesn't have to manually take attendance and no one will be marked absent. +* In ``intranet/apps/eighth/views/admin/blocks.py``, everything that has been changed is placed between two lines of comments and is behind an if statement checking if the ``ENABLE_HYBRID_EIGHTH`` setting is ``True``. In ``edit_block_view``, a simple warning is given that changing a block name will not change the students that are stickied for that block. Trying to to this here just creates conflicts. 8PO is encouraged to just delete the block and create a new one. In ``add_block_view``, different ``visable_blocks`` are shown and additional context is added. If the "assign_hybrid" checkbox is checked, the appropriate groups will be sticked into the correct admin activity according to comments provided throughout and the naming conventions above. As a note, ``attendance_taken`` is set to true, although ``was_absent`` in ``EighthSignup`` is left blank. This is so that 8PO doesn't have to manually take attendance and no one will be marked absent. * In ``intranet/apps/eighth/tasks.py``, a celery task for hybrid signups is added. *********** Signups *********** -The block creation is all set up now, but let's improve user friendliness. For teachers/admin, this involves organizing their Activity Schedule widget and reminding them to take attendance for both of their blocks. For students, this involves organizing their Upcoming Eighth Periods widget to show only the ones they can sign up for and doing something similar to the Signup tab. It's a lot of changing little lines and passing context, but there are some more interesting querys in here. +The block creation is all set up now, but let's improve user friendliness. For teachers/admin, this involves organizing their Activity Schedule widget and reminding them to take attendance for both of their blocks. For students, this involves organizing their Upcoming Eighth Periods widget to show only the ones they can sign up for and doing something similar to the Signup tab. It's a lot of changing little lines and passing context, but there are some more interesting queries in here. * In ``intranet/apps/eighth/models.py``, a property called ``hybrid_text`` is added to ``EighthBlock`` (between two lines of comments) which essentially takes the block names above and makes them more palatable for the end user. @@ -65,12 +65,12 @@ The block creation is all set up now, but let's improve user friendliness. For t * In ``intranet/templates/eighth/profile_signup.html``, two lines are changed to use ``block.hybrid_text`` instead of ``block.block_letter``. -As I noted above, you (person reading this) probably have eighth_admin priviledges on production Ion and certainly have them on your dev environement. This means you WILL see all the blocks except in the widget on the dashboard. Log in as an unpriviledged student to get the full effect of the hidden activities. +As I noted above, you (person reading this) probably have eighth_admin privileges on production Ion and certainly have them on your dev environment. This means you WILL see all the blocks except in the widget on the dashboard. Log in as an unprivileged student to get the full effect of the hidden activities. *********** Admin *********** -At the request of 8PO, some normal eighth period admin actions that they use a lot are rewritten and placed in a seperate "Hybrid" section. The intention of this section is to give them tools adapted to the above configuration. The reason that I didn't modify the regular action is twofold: (a) IF this ever actually gets used, I want it to be easy to revert and (b) there is quite probably going to be a transition period where we are still virtual and doing normal eighth periods, but these hybrid changes are up. The understanding is that these functions assume a block is hybrid and won't work as expected when hybrid blocks aren't being used. The functions won't break if used with non-hybrid blocks, but I'd rather leave the originals to use in this case. 8PO understands and is good with this line of reasoning. +At the request of 8PO, some normal eighth period admin actions that they use a lot are rewritten and placed in a separate "Hybrid" section. The intention of this section is to give them tools adapted to the above configuration. The reason that I didn't modify the regular action is twofold: (a) IF this ever actually gets used, I want it to be easy to revert and (b) there is quite probably going to be a transition period where we are still virtual and doing normal eighth periods, but these hybrid changes are up. The understanding is that these functions assume a block is hybrid and won't work as expected when hybrid blocks aren't being used. The functions won't break if used with non-hybrid blocks, but I'd rather leave the originals to use in this case. 8PO understands and is good with this line of reasoning. * In ``intranet/apps/eighth/views/admin/general.py``, context is passed in the dashboard view based on the ENABLE_HYBRID_EIGHTH setting. diff --git a/intranet/apps/eighth/forms/admin/activities.py b/intranet/apps/eighth/forms/admin/activities.py index d81a7744b19..9e839d711e2 100644 --- a/intranet/apps/eighth/forms/admin/activities.py +++ b/intranet/apps/eighth/forms/admin/activities.py @@ -22,14 +22,14 @@ def __init__(self, *args, **kwargs): def label_from_instance(self, obj): if self.cancelled_acts and obj in self.cancelled_acts: - return "{}: {} (CANCELLED)".format(obj.aid, obj.name) + return f"{obj.aid}: {obj.name} (CANCELLED)" - return "{}: {}".format(obj.aid, obj.name) + return f"{obj.aid}: {obj.name}" class ActivityMultiDisplayField(forms.ModelMultipleChoiceField): def label_from_instance(self, obj): - return "{}: {}".format(obj.aid, obj.name) + return f"{obj.aid}: {obj.name}" class ActivitySelectionForm(forms.Form): @@ -140,18 +140,16 @@ def __init__(self, *args, **kwargs): self.fields["default_capacity"].help_text = "Overrides the sum of each room's capacity above, if set." # These fields are rendered on the right of the page on the edit activity page. - self.right_fields = set( - [ - "restricted", - "users_allowed", - "groups_allowed", - "users_blacklisted", - "freshmen_allowed", - "sophomores_allowed", - "juniors_allowed", - "seniors_allowed", - ] - ) + self.right_fields = { + "restricted", + "users_allowed", + "groups_allowed", + "users_blacklisted", + "freshmen_allowed", + "sophomores_allowed", + "juniors_allowed", + "seniors_allowed", + } class Meta: model = EighthActivity diff --git a/intranet/apps/eighth/forms/admin/blocks.py b/intranet/apps/eighth/forms/admin/blocks.py index edeadef33cd..8aec9b4c414 100644 --- a/intranet/apps/eighth/forms/admin/blocks.py +++ b/intranet/apps/eighth/forms/admin/blocks.py @@ -10,7 +10,7 @@ class BlockDisplayField(forms.ModelChoiceField): def label_from_instance(self, obj): - return "{}: {}".format(obj.id, str(obj)) + return f"{obj.id}: {obj}" class BlockSelectionForm(forms.Form): @@ -47,7 +47,7 @@ def __init__(self, *args, label="Block", exclude_before_date=None, only_locked=F eighthscheduledactivity__in=EighthScheduledActivity.objects.filter(activity__name="z - Hybrid Sticky") ): blocks_set.add((str(b.date), b.block_letter[0])) - queryset = [(b, "{} ({})".format(b[0], b[1])) for b in sorted(list(blocks_set))] + queryset = [(b, f"{b[0]} ({b[1]})") for b in sorted(blocks_set)] queryset.append(("", "Select or search for a block")) self.fields["block"] = forms.ChoiceField(choices=queryset, label=label) diff --git a/intranet/apps/eighth/management/commands/absence_email.py b/intranet/apps/eighth/management/commands/absence_email.py index 0f58d87702a..b10519585d4 100644 --- a/intranet/apps/eighth/management/commands/absence_email.py +++ b/intranet/apps/eighth/management/commands/absence_email.py @@ -19,7 +19,7 @@ def handle(self, *args, **options): for signup in absences: if log: - self.stdout.write("{}".format(signup)) + self.stdout.write(str(signup)) if not options["pretend"]: absence_email(signup) signup.absence_emailed = True diff --git a/intranet/apps/eighth/management/commands/delete_duplicate_signups.py b/intranet/apps/eighth/management/commands/delete_duplicate_signups.py index 8674e639628..2897bad5eaf 100644 --- a/intranet/apps/eighth/management/commands/delete_duplicate_signups.py +++ b/intranet/apps/eighth/management/commands/delete_duplicate_signups.py @@ -17,4 +17,4 @@ def handle(self, *args, **options): signups = EighthSignup.objects.filter(user__id=x["user"], scheduled_activity__block__id=x["scheduled_activity__block"]) signups = EighthSignup.objects.filter(pk__in=signups.order_by("-time").values_list("pk")[1:]) signups.delete() - sys.stdout.write("Deleted {} duplicate signup(s).\n".format(num_duplicates)) + sys.stdout.write(f"Deleted {num_duplicates} duplicate signup(s).\n") diff --git a/intranet/apps/eighth/management/commands/find_duplicates.py b/intranet/apps/eighth/management/commands/find_duplicates.py index ad267575cfe..6add9425d26 100644 --- a/intranet/apps/eighth/management/commands/find_duplicates.py +++ b/intranet/apps/eighth/management/commands/find_duplicates.py @@ -21,16 +21,16 @@ def handle(self, *args, **options): return for uid, bid in duplicates: su = EighthSignup.objects.filter(user_id=uid, scheduled_activity__block_id=bid) - self.stdout.write("Duplicate: {} {}".format(uid, bid)) + self.stdout.write(f"Duplicate: {uid} {bid}") self.stdout.write("Scheduled activities: %s" % su) if options["fix"]: if su[0].scheduled_activity.activity.both_blocks: sibling = su[0].scheduled_activity.get_both_blocks_sibling() if EighthSignup.objects.filter(user_id=uid, scheduled_activity=sibling).exists(): - self.stdout.write("Deleted su1 {}".format(su[1])) + self.stdout.write(f"Deleted su1 {su[1]}") su[1].delete() elif su[1].scheduled_activity.activity.both_blocks: sibling = su[1].scheduled_activity.get_both_blocks_sibling() if EighthSignup.objects.filter(user_id=uid, scheduled_activity=sibling).exists(): - self.stdout.write("Deleted su0 {}".format(su[0])) + self.stdout.write(f"Deleted su0 {su[0]}") su[0].delete() diff --git a/intranet/apps/eighth/management/commands/generate_similarities.py b/intranet/apps/eighth/management/commands/generate_similarities.py index cd3e709f56f..bf908a3bbd2 100644 --- a/intranet/apps/eighth/management/commands/generate_similarities.py +++ b/intranet/apps/eighth/management/commands/generate_similarities.py @@ -39,7 +39,7 @@ def handle(self, *args, **options): sim.activity_set.add(act, act2) sim.count = 1 sim.save() - print("Finished similarities for {} in {} seconds".format(act, time.time() - start_act)) + print(f"Finished similarities for {act} in {time.time() - start_act} seconds") for act in acts: if act.is_popular: for sim in act.similarities.all(): @@ -47,4 +47,4 @@ def handle(self, *args, **options): sim.save() for sim in EighthActivitySimilarity.objects.all(): sim.update_weighted() - print("Generated similarities in {} seconds".format(time.time() - start)) + print(f"Generated similarities in {time.time() - start} seconds") diff --git a/intranet/apps/eighth/management/commands/remove_withdrawn_students.py b/intranet/apps/eighth/management/commands/remove_withdrawn_students.py index 75c49c148a4..338cca7a4ba 100644 --- a/intranet/apps/eighth/management/commands/remove_withdrawn_students.py +++ b/intranet/apps/eighth/management/commands/remove_withdrawn_students.py @@ -29,7 +29,7 @@ def handle(self, *args, **options): base_url = "https://ion.tjhsst.edu" data = { "withdrawn_group_str": str(group), - "users": ["{} ({})".format(u.full_name, u.username) for u in group.user_set.all()], + "users": [f"{u.full_name} ({u.username})" for u in group.user_set.all()], "help_email": settings.FEEDBACK_EMAIL, "base_url": base_url, "info_link": base_url, @@ -41,11 +41,11 @@ def handle(self, *args, **options): "eighth/emails/withdrawn_students.txt", "eighth/emails/withdrawn_students.html", data, - "Withdrawn Students on {}".format(str(timezone.localdate())), + f"Withdrawn Students on {timezone.localdate()}", NOTIFY_EMAILS, ) for user in group.user_set.all(): - self.stdout.write("Deleting {}\n".format(user)) + self.stdout.write(f"Deleting {user}\n") user.handle_delete() self.stdout.write(str(user.delete()) + "\n") diff --git a/intranet/apps/eighth/management/commands/signup_status_email.py b/intranet/apps/eighth/management/commands/signup_status_email.py index 71143390064..b527dddd7d9 100644 --- a/intranet/apps/eighth/management/commands/signup_status_email.py +++ b/intranet/apps/eighth/management/commands/signup_status_email.py @@ -45,27 +45,27 @@ def handle(self, *args, **options): blk_date = next_blocks[0].date if blk_date != tomorrow: if log: - self.stdout.write("Block {} on {} is not tomorrow ({}).".format(next_blocks[0], blk_date, tomorrow)) + self.stdout.write(f"Block {next_blocks[0]} on {blk_date} is not tomorrow ({tomorrow}).") return if options["only-today"]: blk_date = next_blocks[0].date if blk_date != today: if log: - self.stdout.write("Block {} on {} is not today ({}).".format(next_blocks[0], blk_date, today)) + self.stdout.write(f"Block {next_blocks[0]} on {blk_date} is not today ({today}).") return if log: - self.stdout.write("{}".format(next_blocks)) - self.stdout.write("{}".format(options)) - self.stdout.write("{}".format(users)) + self.stdout.write(str(next_blocks)) + self.stdout.write(str(options)) + self.stdout.write(str(users)) for user in users: user_signups = EighthSignup.objects.filter(user=user, scheduled_activity__block__in=next_blocks) if user_signups.count() < next_blocks.count(): """User hasn't signed up for a block.""" if log: - self.stdout.write("User {} hasn't signed up for a block".format(user)) + self.stdout.write(f"User {user} hasn't signed up for a block") if not options["pretend"]: try: signup_status_email(user, next_blocks) @@ -74,7 +74,7 @@ def handle(self, *args, **options): elif user_signups.filter(scheduled_activity__cancelled=True).count() > 0: """User is in a cancelled activity.""" if log: - self.stdout.write("User {} is in a cancelled activity.".format(user)) + self.stdout.write(f"User {user} is in a cancelled activity.") if not options["pretend"]: try: signup_status_email(user, next_blocks) diff --git a/intranet/apps/eighth/management/commands/update_counselors.py b/intranet/apps/eighth/management/commands/update_counselors.py index 4ffec764833..2d1da7c4e0e 100644 --- a/intranet/apps/eighth/management/commands/update_counselors.py +++ b/intranet/apps/eighth/management/commands/update_counselors.py @@ -43,11 +43,11 @@ def handle(self, *args, **kwargs): counselor = counselors.get(last_name=counselor) u = get_user_model().objects.user_with_student_id(sid) if u is None: - sys.stdout.write("There is no Ion account found for SID {}\n".format(sid)) + sys.stdout.write(f"There is no Ion account found for SID {sid}\n") continue if counselor != u.counselor: - sys.stdout.write("Switching counselor for SID {} from {} to {}\n".format(sid, u.counselor, counselor)) + sys.stdout.write(f"Switching counselor for SID {sid} from {u.counselor} to {counselor}\n") if to_run: u.counselor = counselor u.save() diff --git a/intranet/apps/eighth/models.py b/intranet/apps/eighth/models.py index aa4d6798526..209f4ece0c1 100644 --- a/intranet/apps/eighth/models.py +++ b/intranet/apps/eighth/models.py @@ -153,10 +153,10 @@ def formatted_name(self) -> str: """ if self.name[0] in string.digits: # All rooms starting with an integer will be prefixed - return "Rm. {}".format(self.name) + return f"Rm. {self.name}" if self.name.startswith("Room"): # Some room names are prefixed with 'Room'; for consistency - return "Rm. {}".format(self.name[5:]) + return f"Rm. {self.name[5:]}" return self.name @property @@ -165,7 +165,7 @@ def to_be_determined(self) -> bool: return any(x in self.name.lower() for x in ["to be assigned", "to be determined", "to be announced"]) def __str__(self): - return "{} ({})".format(self.name, self.capacity) + return f"{self.name} ({self.capacity})" class Meta: ordering = ("name",) @@ -325,7 +325,7 @@ def _name_with_flags(self, include_restricted: bool, title: Optional[str] = None name = "Special: " if self.special else "" name += self.name if title: - name += " - {}".format(title) + name += f" - {title}" name += " (R)" if include_restricted and self.restricted else "" name += " (BB)" if self.both_blocks else "" @@ -348,7 +348,7 @@ def restricted_activities_available_to_user(cls, user: "get_user_model()") -> Li q = Q(users_allowed=user.id) | Q(groups_allowed__user=user.id) if user and user.grade and user.grade.number and user.grade.name and 9 <= user.grade.number <= 12: - q |= Q(**{"{}_allowed".format(user.grade.name_plural): True}) + q |= Q(**{f"{user.grade.name_plural}_allowed": True}) return EighthActivity.objects.filter(q).values_list("id", flat=True) @@ -391,7 +391,7 @@ def frequent_users(self) -> Union[QuerySet, Collection["get_user_model()"]]: # Returns: A QuerySet of users who attend this activity frequently. """ - key = "eighthactivity_{}:frequent_users".format(self.id) + key = f"eighthactivity_{self.id}:frequent_users" cached = cache.get(key) if cached: return cached @@ -574,7 +574,7 @@ def previous_blocks(self, quantity: int = -1) -> Union[QuerySet, Collection["Eig Args: quantity: The number of blocks to list before this block, or -1 for all previous blocks. Returns: - If `quantity` is not passed, retuns a QuerySet with all the blocks this school year + If `quantity` is not passed, returns a QuerySet with all the blocks this school year before this block. If `quantity` is passed, returns a list with the specified number of blocks this school year before this block. @@ -720,10 +720,10 @@ def formatted_date(self) -> str: def __str__(self): ####### if settings.ENABLE_HYBRID_EIGHTH: - return "{} ({})".format(self.formatted_date, self.hybrid_text) + return f"{self.formatted_date} ({self.hybrid_text})" else: ####### - return "{} ({})".format(self.formatted_date, self.block_letter) + return f"{self.formatted_date} ({self.block_letter})" class Meta: unique_together = (("date", "block_letter"),) @@ -841,7 +841,7 @@ def full_title(self) -> str: act_name = self.activity.name + cancelled_str if self.special and not self.activity.special: act_name = "Special: " + act_name - return act_name if not self.title else "{} - {}".format(act_name, self.title) + return act_name if not self.title else f"{act_name} - {self.title}" @property def title_with_flags(self) -> str: @@ -1010,7 +1010,7 @@ def _get_viewable_members( Args: user: The user who is attempting to view the member list. Returns: - Unsorted QuerySet of the members that you have permssion to view. + Unsorted QuerySet of the members that you have permission to view. """ if user and (user.is_eighth_admin or user.is_eighthoffice or user.is_teacher): return self.members.all() @@ -1037,7 +1037,7 @@ def get_viewable_members_serializer(self, request) -> Union[QuerySet, Collection Args: request: The request object associated with the member list query. Returns: - Unsorted QuerySet of the members that you have permssion to view. + Unsorted QuerySet of the members that you have permission to view. """ return self._get_viewable_members(request.user) @@ -1252,7 +1252,7 @@ def add_user( except EighthSignup.DoesNotExist: add_breadcrumb( category="eighth-signup", - message="Signing user {} up for single-block activity {} in block {}".format(user.id, self.activity.id, self.block.id), + message=f"Signing user {user.id} up for single-block activity {self.activity.id} in block {self.block.id}", level="debug", ) @@ -1296,9 +1296,7 @@ def add_user( if not existing_signup.scheduled_activity.is_both_blocks(): add_breadcrumb( category="eighth-signup", - message="Switching user {} from single-block activity {} to single-block activity {} in block {}".format( - user.id, existing_signup.scheduled_activity.activity.id, self.activity.id, self.block.id - ), + message=f"Switching user {user.id} from single-block activity {existing_signup.scheduled_activity.activity.id} to single-block activity {self.activity.id} in block {self.block.id}", # pylint: disable=line-too-long # noqa: E501 level="debug", ) @@ -1354,9 +1352,7 @@ def add_user( add_breadcrumb( category="eighth-signup", - message="Switching user {} from dual-block activity {} to single-block activity {} in block {}".format( - user.id, existing_signup.scheduled_activity.activity.id, self.activity.id, self.block.id - ), + message=f"Switching user {user.id} from dual-block activity {existing_signup.scheduled_activity.activity.id} to single-block activity {self.activity.id} in block {self.block.id}", # pylint: disable=line-too-long # noqa: E501 level="debug", ) @@ -1433,9 +1429,7 @@ def add_user( for signup in existing_signups: add_breadcrumb( category="eighth-signup", - message="User {}: original activity for block {}: {}".format( - user.id, signup.scheduled_activity.block.id, signup.scheduled_activity.activity.id - ), + message=f"User {user.id}: original activity for block {signup.scheduled_activity.block.id}: {signup.scheduled_activity.activity.id}", # pylint: disable=line-too-long # noqa: E501 level="debug", ) @@ -1457,7 +1451,7 @@ def add_user( add_breadcrumb( category="eighth-signup", - message="Switching user {} to double-block activity {} in block {}".format(user.id, sched_act.id, self.block.id), + message=f"Switching user {user.id} to double-block activity {sched_act.id} in block {self.block.id}", level="debug", ) @@ -1541,8 +1535,8 @@ class Meta: def __str__(self): cancelled_str = " (Cancelled)" if self.cancelled else "" - suff = " - {}".format(self.title) if self.title else "" - return "{}{} on {}{}".format(self.activity, suff, self.block, cancelled_str) + suff = f" - {self.title}" if self.title else "" + return f"{self.activity}{suff} on {self.block}{cancelled_str}" class EighthSignupManager(Manager): @@ -1715,7 +1709,7 @@ def remove_signup(self, user: "get_user_model()" = None, force: bool = False, do if not self.scheduled_activity.is_full(): waitlists = EighthWaitlist.objects.get_next_waitlist(self.scheduled_activity) self.scheduled_activity.notify_waitlist(waitlists) - return "Successfully removed signup for {}.".format(block) + return f"Successfully removed signup for {block}." def accept_pass(self): """Accepts an eighth period pass for the EighthSignup object.""" @@ -1744,7 +1738,7 @@ def archive_remove_absence(self): self.save(update_fields=["was_absent", "archived_was_absent"]) def __str__(self): - return "{}: {}".format(self.user, self.scheduled_activity) + return f"{self.user}: {self.scheduled_activity}" class Meta: unique_together = (("user", "scheduled_activity"),) @@ -1801,7 +1795,7 @@ class EighthWaitlist(AbstractBaseEighthModel): ) def __str__(self): - return "{}: {}".format(self.user, self.scheduled_activity) + return f"{self.user}: {self.scheduled_activity}" class EighthActivitySimilarity(AbstractBaseEighthModel): @@ -1822,4 +1816,4 @@ def update_weighted(self): def __str__(self): act_set = self.activity_set.all() - return "{} and {}: {}".format(act_set.first(), act_set.last(), self.count) + return f"{act_set.first()} and {act_set.last()}: {self.count}" diff --git a/intranet/apps/eighth/notifications.py b/intranet/apps/eighth/notifications.py index 1b208016e43..738c475a039 100644 --- a/intranet/apps/eighth/notifications.py +++ b/intranet/apps/eighth/notifications.py @@ -32,7 +32,7 @@ def signup_status_email(user, next_blocks, use_celery=True): block_date = next_blocks[0].date block_signup_time = next_blocks[0].signup_time if block_signup_time: - block_signup_time = "{}:{}".format(block_signup_time.hour, block_signup_time.minute) + block_signup_time = f"{block_signup_time.hour}:{block_signup_time.minute}" date_str = block_date.strftime("%A, %B %-d") @@ -50,7 +50,7 @@ def signup_status_email(user, next_blocks, use_celery=True): "info_link": base_url + reverse("eighth_signup"), } - args = ("eighth/emails/signup_status.txt", "eighth/emails/signup_status.html", data, "Signup Status for {}".format(date_str), emails) + args = ("eighth/emails/signup_status.txt", "eighth/emails/signup_status.html", data, f"Signup Status for {date_str}", emails) if use_celery: email_send_task.delay(*args) return None @@ -81,7 +81,7 @@ def activity_cancelled_email(sched_act: EighthScheduledActivity): "eighth/emails/activity_cancelled.txt", "eighth/emails/activity_cancelled.html", data, - "Activity Cancelled on {}".format(date_str), + f"Activity Cancelled on {date_str}", emails, bcc=True, ) diff --git a/intranet/apps/eighth/serializers.py b/intranet/apps/eighth/serializers.py index d20a45e3d30..d3dc07cfbb4 100644 --- a/intranet/apps/eighth/serializers.py +++ b/intranet/apps/eighth/serializers.py @@ -223,9 +223,9 @@ def fetch_activity_list_with_metadata(self, block): sponsors_dict = EighthSponsor.objects.values_list("id", "user_id", "first_name", "last_name", "show_full_name") - all_sponsors = dict( - (sponsor[0], {"user_id": sponsor[1], "name": sponsor[2] + " " + sponsor[3] if sponsor[4] else sponsor[3]}) for sponsor in sponsors_dict - ) + all_sponsors = { + sponsor[0]: {"user_id": sponsor[1], "name": sponsor[2] + " " + sponsor[3] if sponsor[4] else sponsor[3]} for sponsor in sponsors_dict + } activity_ids = scheduled_activities.values_list("activity__id") sponsorships = ( diff --git a/intranet/apps/eighth/tasks.py b/intranet/apps/eighth/tasks.py index b2b61f588f1..50e97178cf9 100644 --- a/intranet/apps/eighth/tasks.py +++ b/intranet/apps/eighth/tasks.py @@ -20,7 +20,9 @@ @shared_task def room_changed_single_email( - sched_act: EighthScheduledActivity, old_rooms: Collection[EighthRoom], new_rooms: Collection[EighthRoom] # pylint: disable=unsubscriptable-object + sched_act: EighthScheduledActivity, + old_rooms: Collection[EighthRoom], + new_rooms: Collection[EighthRoom], # pylint: disable=unsubscriptable-object ): # pylint: disable=unsubscriptable-object """Notifies all the users signed up for the given EighthScheduledActivity that it is changing rooms. @@ -62,7 +64,7 @@ def room_changed_single_email( "eighth/emails/room_changed_single.txt", "eighth/emails/room_changed_single.html", data, - "Room change for {} on {}".format(sched_act.activity.name, date_str), + f"Room change for {sched_act.activity.name} on {date_str}", emails, bcc=True, ) @@ -70,7 +72,9 @@ def room_changed_single_email( @shared_task def transferred_activity_email( - dest_act: EighthScheduledActivity, source_act: EighthScheduledActivity, duplicate_students # pylint: disable=unsubscriptable-object + dest_act: EighthScheduledActivity, + source_act: EighthScheduledActivity, + duplicate_students, # pylint: disable=unsubscriptable-object ): # pylint: disable=unsubscriptable-object """Notifies all the users already signed up for an EighthScheduledActivity that they have been transferred into a new activity. @@ -108,7 +112,7 @@ def transferred_activity_email( "eighth/emails/transferred_activity.txt", "eighth/emails/transferred_activity.html", data, - "8th Period Transfer to {} on {}".format(dest_act.activity.name, date_str), + f"8th Period Transfer to {dest_act.activity.name} on {date_str}", emails, bcc=True, ) @@ -116,10 +120,12 @@ def transferred_activity_email( @shared_task def room_changed_activity_email( - act: EighthActivity, old_rooms: Collection[EighthRoom], new_rooms: Collection[EighthRoom] # pylint: disable=unsubscriptable-object + act: EighthActivity, + old_rooms: Collection[EighthRoom], + new_rooms: Collection[EighthRoom], # pylint: disable=unsubscriptable-object ): # pylint: disable=unsubscriptable-object """Notifies all the users signed up for the given EighthActivity on the blocks for which the room - list is not overriden that it is changing rooms. + list is not overridden that it is changing rooms. Args: act: The activity that has changed rooms. @@ -164,7 +170,7 @@ def room_changed_activity_email( "eighth/emails/room_changed_activity.txt", "eighth/emails/room_changed_activity.html", data, - "Room changes for {}".format(act.name), + f"Room changes for {act.name}", [user.notification_email], bcc=True, ) @@ -334,7 +340,7 @@ def follow_up_absence_emails(): "eighth/emails/absence_monthly.txt", "eighth/emails/absence_monthly.html", data, - "{} Uncleared Eighth Period Absences".format(num_absences), + f"{num_absences} Uncleared Eighth Period Absences", [student.notification_email], bcc=True, ) diff --git a/intranet/apps/eighth/tests/admin/test_admin_general.py b/intranet/apps/eighth/tests/admin/test_admin_general.py index ceeefcbdc9d..bc348dd83bb 100644 --- a/intranet/apps/eighth/tests/admin/test_admin_general.py +++ b/intranet/apps/eighth/tests/admin/test_admin_general.py @@ -23,11 +23,11 @@ def test_eighth_admin_dashboard_view(self): user = self.make_admin() for i in range(1, 21): - self.add_activity(name="Test{}".format(i)) - Group.objects.create(name="Test{}".format(i)) - user = get_user_model().objects.create(username="awilliam{}".format(i)) - EighthRoom.objects.create(name="Test{}".format(i)) - EighthSponsor.objects.create(user=user, first_name="Angela{}".format(i), last_name="William") + self.add_activity(name=f"Test{i}") + Group.objects.create(name=f"Test{i}") + user = get_user_model().objects.create(username=f"awilliam{i}") + EighthRoom.objects.create(name=f"Test{i}") + EighthSponsor.objects.create(user=user, first_name=f"Angela{i}", last_name="William") self.add_block(date="9001-4-20", block_letter="A") diff --git a/intranet/apps/eighth/tests/admin/test_admin_groups.py b/intranet/apps/eighth/tests/admin/test_admin_groups.py index 0c429cefbcc..1e233038d46 100644 --- a/intranet/apps/eighth/tests/admin/test_admin_groups.py +++ b/intranet/apps/eighth/tests/admin/test_admin_groups.py @@ -39,7 +39,7 @@ def test_edit_group_view(self): response = self.client.get(reverse("eighth_admin_edit_group", kwargs={"group_id": group.id})) self.assertEqual(200, response.status_code) - # Addding users tested in test_add_member_to_group_view below + # Adding users tested in test_add_member_to_group_view below # Add three users user1 = get_user_model().objects.get_or_create(username="2021ttest", first_name="Tommy", last_name="Test")[0] @@ -84,7 +84,7 @@ def test_upload_group_members_view(self): user3 = get_user_model().objects.get_or_create(username="2021awilliam", first_name="A", last_name="William")[0] # Add user1 by file upload - file_obj = SimpleUploadedFile("users.csv", "2021ttest\n".encode("UTF-8"), content_type="text/csv") + file_obj = SimpleUploadedFile("users.csv", b"2021ttest\n", content_type="text/csv") response = self.client.post(reverse("eighth_admin_upload_group_members", kwargs={"group_id": group.id}), data={"file": file_obj}) self.assertEqual(200, response.status_code) self.assertEqual("parse", response.context["stage"]) @@ -535,21 +535,21 @@ def test_delete_empty_groups(self): userB = get_user_model().objects.get_or_create(username="userB")[0] # Create groups - groupEmpty = Group.objects.get_or_create(name="Empty Group")[0] - groupNotEmpty = Group.objects.get_or_create(name="Not Empty Group")[0] + group_empty = Group.objects.get_or_create(name="Empty Group")[0] + group_not_empty = Group.objects.get_or_create(name="Not Empty Group")[0] # Add users to group - groupNotEmpty.user_set.add(userA) - groupNotEmpty.user_set.add(userB) + group_not_empty.user_set.add(userA) + group_not_empty.user_set.add(userB) response = self.client.post(reverse("eighth_admin_delete_empty_groups_view")) self.assertEqual(response.status_code, 302) - self.assertNotIn(groupEmpty, Group.objects.all()) + self.assertNotIn(group_empty, Group.objects.all()) # Add user to other group - groupNotEmpty.user_set.remove(userA) - groupNotEmpty.user_set.remove(userB) + group_not_empty.user_set.remove(userA) + group_not_empty.user_set.remove(userB) response = self.client.post(reverse("eighth_admin_delete_empty_groups_view")) self.assertEqual(response.status_code, 302) - self.assertNotIn(groupNotEmpty, Group.objects.all()) + self.assertNotIn(group_not_empty, Group.objects.all()) diff --git a/intranet/apps/eighth/tests/test_activities.py b/intranet/apps/eighth/tests/test_activities.py index 382a7db0855..df7bdb3735b 100644 --- a/intranet/apps/eighth/tests/test_activities.py +++ b/intranet/apps/eighth/tests/test_activities.py @@ -169,7 +169,7 @@ def test_activity_stats(self): "start": "2020-10-01", "end": "2020-10-24", "freshmen": "on", - "sophmores": "on", + "sophomores": "on", "juniors": "on", "seniors": "on", }, @@ -184,7 +184,7 @@ def test_activity_stats(self): "start": "2013-01-01", "end": "2020-10-24", "freshmen": "on", - "sophmores": "on", + "sophomores": "on", "juniors": "on", "seniors": "on", }, diff --git a/intranet/apps/eighth/tests/test_attendance.py b/intranet/apps/eighth/tests/test_attendance.py index 64b4bc57da7..94db24bfa02 100644 --- a/intranet/apps/eighth/tests/test_attendance.py +++ b/intranet/apps/eighth/tests/test_attendance.py @@ -16,7 +16,7 @@ class EighthAttendanceTestCase(EighthAbstractTest): """Test cases for ``views.attendance``.""" def test_take_attendance(self): - """Makes sure that taking attendance for activites with multiple students signed up works.""" + """Makes sure that taking attendance for activities with multiple students signed up works.""" self.make_admin() user1 = get_user_model().objects.create( @@ -82,7 +82,7 @@ def test_take_attendance_clear_bit(self): self.assertFalse(EighthScheduledActivity.objects.get(block=block, activity=activity).attendance_taken) def test_take_attendance_google_meet_csv(self): - """Make sure taking attendence through an uploaded Google Meet file works.""" + """Make sure taking attendance through an uploaded Google Meet file works.""" self.make_admin() user1 = get_user_model().objects.create( username="user1", graduation_year=get_senior_graduation_year() + 1, student_id=12345, first_name="Test", last_name="User" diff --git a/intranet/apps/eighth/tests/test_exceptions.py b/intranet/apps/eighth/tests/test_exceptions.py index 03a3d41f275..04c0b859f4c 100644 --- a/intranet/apps/eighth/tests/test_exceptions.py +++ b/intranet/apps/eighth/tests/test_exceptions.py @@ -31,4 +31,4 @@ def test_signup_exception(self): # Test string representations self.assertEqual(str(signup_exception), "ScheduledActivityCancelled, SignupForbidden") - self.assertEqual(repr(signup_exception), "SignupException({})".format(str(signup_exception))) + self.assertEqual(repr(signup_exception), f"SignupException({signup_exception})") diff --git a/intranet/apps/eighth/views/activities.py b/intranet/apps/eighth/views/activities.py index 0d6397184bb..834fd65879e 100644 --- a/intranet/apps/eighth/views/activities.py +++ b/intranet/apps/eighth/views/activities.py @@ -159,13 +159,13 @@ def generate_statistics_pdf(activities=None, start_date=None, all_years=False, y Table(x, style=[("FONT", (0, 0), (-1, 0), "Helvetica-Bold"), ("LEFTPADDING", (0, 0), (-1, -1), 0)]) for x in empty_activities ] for i in range(0, len(empty_activities), 2): - elements.append(Paragraph("Empty Activities (Page {})".format(i // 2 + 1), styles["Title"])) + elements.append(Paragraph(f"Empty Activities (Page {i // 2 + 1})", styles["Title"])) if all_years: elements.append(Paragraph("The following activities have no 8th period blocks assigned to them.", styles["Normal"])) else: elements.append( Paragraph( - "The following activities have no 8th period blocks assigned to them for the {}-{} school year.".format(year - 1, year), + f"The following activities have no 8th period blocks assigned to them for the {year - 1}-{year} school year.", styles["Normal"], ) ) @@ -184,7 +184,7 @@ def generate_statistics_pdf(activities=None, start_date=None, all_years=False, y def first_page(canvas, _): if len(activities) == 1: - canvas.setTitle("{} Statistics".format(activities[0].name)) + canvas.setTitle(f"{activities[0].name} Statistics") else: canvas.setTitle("8th Period Activity Statistics") canvas.setAuthor("Generated by Ion") diff --git a/intranet/apps/eighth/views/admin/activities.py b/intranet/apps/eighth/views/admin/activities.py index d43eaec44f6..eabf4092305 100644 --- a/intranet/apps/eighth/views/admin/activities.py +++ b/intranet/apps/eighth/views/admin/activities.py @@ -79,9 +79,7 @@ def edit_activity_view(request, activity_id): for sponsor in old_sponsors: sa.sponsors.add(sponsor) sa.save() - messages.success( - request, "Overrode {} scheduled activities to old sponsor default".format(sched_acts_default.count()) - ) + messages.success(request, f"Overrode {sched_acts_default.count()} scheduled activities to old sponsor default") elif change == "no": # Don't override messages.success(request, "Changing default sponsors globally") @@ -126,7 +124,7 @@ def edit_activity_view(request, activity_id): # Override old entries for sa in sched_acts_default: sa.rooms.set(old_rooms) - messages.success(request, "Overrode {} scheduled activities to old room default".format(sched_acts_default.count())) + messages.success(request, f"Overrode {sched_acts_default.count()} scheduled activities to old room default") elif change == "no": # Don't override messages.success(request, "Changing default rooms globally") @@ -169,7 +167,7 @@ def edit_activity_view(request, activity_id): EighthWaitlist.objects.filter(scheduled_activity=sa).delete() messages.success(request, "Successfully edited activity.") if "add_group" in request.POST: - grp_name = "Activity: {}".format(activity.name) + grp_name = f"Activity: {activity.name}" grp, status = Group.objects.get_or_create(name=grp_name) activity.restricted = True activity.groups_allowed.add(grp) @@ -190,7 +188,7 @@ def edit_activity_view(request, activity_id): for g in activity.groups_allowed.all(): group = {} group["id"] = g.id - group["name"] = "{}".format(g) + group["name"] = str(g) group["members_alpha"] = sorted(g.user_set.all(), key=lambda x: (x.last_name, x.first_name)) group["members_alpha_count"] = len(group["members_alpha"]) activity_groups.append(group) diff --git a/intranet/apps/eighth/views/admin/attendance.py b/intranet/apps/eighth/views/admin/attendance.py index 5e623f1e5ef..000c319daaf 100644 --- a/intranet/apps/eighth/views/admin/attendance.py +++ b/intranet/apps/eighth/views/admin/attendance.py @@ -178,8 +178,8 @@ def no_signups_roster(request, block_id): for user in unsigned: row = [] - row.append("{}".format(block.id)) - row.append("{}".format(block)) + row.append(str(block.id)) + row.append(str(block)) row.append(user.last_name) row.append(user.first_name) row.append(user.student_id) @@ -285,10 +285,10 @@ def activities_without_attendance_view(request): logger.debug(zero_students) if signups.count() == 0: zero_students.update(attendance_taken=True) - messages.success(request, "Took attendance for {} empty activities.".format(zero_students.count())) + messages.success(request, f"Took attendance for {zero_students.count()} empty activities.") else: - messages.error(request, "Apparently there were actually {} signups. Maybe one is no longer empty?".format(signups.count())) - return redirect("/eighth/admin/attendance/no_attendance?block={}".format(block.id)) + messages.error(request, f"Apparently there were actually {signups.count()} signups. Maybe one is no longer empty?") + return redirect(f"/eighth/admin/attendance/no_attendance?block={block.id}") if request.POST.get("take_attendance_cancelled", False) is not False: cancelled = scheduled_activities.filter(cancelled=True) @@ -297,10 +297,8 @@ def activities_without_attendance_view(request): logger.debug(signups) signups.update(was_absent=True) cancelled.update(attendance_taken=True) - messages.success( - request, "Took attendance for {} cancelled activities. {} students marked absent.".format(cancelled.count(), signups.count()) - ) - return redirect("/eighth/admin/attendance/no_attendance?block={}".format(block.id)) + messages.success(request, f"Took attendance for {cancelled.count()} cancelled activities. {signups.count()} students marked absent.") + return redirect(f"/eighth/admin/attendance/no_attendance?block={block.id}") context["admin_page_title"] = "Activities That Haven't Taken Attendance" return render(request, "eighth/admin/activities_without_attendance.html", context) @@ -376,7 +374,7 @@ def out_of_building_schedules_view(request, block_id=None): else: response = http.HttpResponse(content_type="text/csv") block_date_str = datetime.strftime(block.date, "%m_%d_%Y") - filename = '"out_of_building_schedules_{}.csv"'.format(block_date_str) + filename = f'"out_of_building_schedules_{block_date_str}.csv"' response["Content-Disposition"] = "attachment; filename=" + filename writer = csv.writer(response) @@ -436,7 +434,7 @@ def open_passes_view(request): rejected += 1 invalidate_obj(signup) - messages.success(request, "Accepted {} and rejected {} passes.".format(accepted, rejected)) + messages.success(request, f"Accepted {accepted} and rejected {rejected} passes.") if request.resolver_match.url_name == "eighth_admin_view_open_passes_csv": response = http.HttpResponse(content_type="text/csv") diff --git a/intranet/apps/eighth/views/admin/blocks.py b/intranet/apps/eighth/views/admin/blocks.py index d255fdf47cf..d3526e7021f 100644 --- a/intranet/apps/eighth/views/admin/blocks.py +++ b/intranet/apps/eighth/views/admin/blocks.py @@ -47,7 +47,7 @@ def add_block_view(request): if date: date_format = re.compile(r"([0-9]{2})\/([0-9]{2})\/([0-9]{4})") fmtdate = date_format.sub(r"\3-\1-\2", date) - title_suffix = " - {}".format(fmtdate) + title_suffix = f" - {fmtdate}" show_letters = True if "modify_blocks" in request.POST: @@ -62,19 +62,19 @@ def add_block_view(request): if ltr not in current_letters: EighthBlock.objects.create(date=fmtdate, block_letter=ltr, signup_time=signup_time) messages.success( - request, "Successfully added {} Block on {} with signups shown to students as closing at {}".format(ltr, fmtdate, signup_time) + request, f"Successfully added {ltr} Block on {fmtdate} with signups shown to students as closing at {signup_time}" ) for ltr in current_letters: if not ltr: continue if ltr not in letters: EighthBlock.objects.get(date=fmtdate, block_letter=ltr).delete() - messages.success(request, "Successfully removed {} Block on {}".format(ltr, fmtdate)) + messages.success(request, f"Successfully removed {ltr} Block on {fmtdate}") else: blk = EighthBlock.objects.get(date=fmtdate, block_letter=ltr) blk.signup_time = signup_time blk.save() - messages.success(request, "Successfully changed the signup time of {} Block on {}".format(ltr, fmtdate)) + messages.success(request, f"Successfully changed the signup time of {ltr} Block on {fmtdate}") invalidate_model(EighthBlock) @@ -130,7 +130,7 @@ def add_block_view(request): letters.append({"name": blk.block_letter, "exists": True}) context = { - "admin_page_title": "Add or Remove Blocks{}".format(title_suffix), + "admin_page_title": f"Add or Remove Blocks{title_suffix}", "date": date, "letters": letters, "show_letters": show_letters, @@ -176,7 +176,7 @@ def perform_hybrid_block_signup(fmtdate, celery_logger): if failed_users: # this shouldn't happen because only students should be in the groups, but we don't want to 500 celery_logger.debug( "Some users could not be stickied. Please handle them manually and let the Ion devs know: {}".format( - ", ".join(["{} {}".format(u.first_name, u.last_name) for u in failed_users]) + ", ".join([f"{u.first_name} {u.last_name}" for u in failed_users]) ) ) elif "P2" in block_names and "Virt" in block_names and "P1" not in block_names: @@ -204,7 +204,7 @@ def perform_hybrid_block_signup(fmtdate, celery_logger): if failed_users: # this shouldn't happen because only students should be in the groups, but we don't want to 500 celery_logger.debug( "Some users could not be stickied. Please handle them manually and let the Ion devs know: {}".format( - ", ".join(["{} {}".format(u.first_name, u.last_name) for u in failed_users]) + ", ".join([f"{u.first_name} {u.last_name}" for u in failed_users]) ) ) @@ -282,7 +282,7 @@ def copy_block_view(request, block_id): "new_activities": EighthScheduledActivity.objects.filter(block=block).count(), "new_signups": EighthSignup.objects.filter(scheduled_activity__block=block).count(), "success": True, - "admin_page_title": "Finished Copy Block - {} ({})".format(block.formatted_date, block.block_letter), + "admin_page_title": f"Finished Copy Block - {block.formatted_date} ({block.block_letter})", "block_id": block_id, } return render(request, "eighth/admin/copy_form.html", context) @@ -294,8 +294,8 @@ def copy_block_view(request, block_id): "existing_activities": EighthScheduledActivity.objects.filter(block=block).count(), "existing_signups": EighthSignup.objects.filter(scheduled_activity__block=block).count(), "blocks": EighthBlock.objects.all().order_by("date"), - "admin_page_title": "Copy Block - {} ({})".format(block.formatted_date, block.block_letter), - "to_block": "{}: {} ({})".format(block.id, block.formatted_date, block.block_letter), + "admin_page_title": f"Copy Block - {block.formatted_date} ({block.block_letter})", + "to_block": f"{block.id}: {block.formatted_date} ({block.block_letter})", "block_id": block_id, "locked": block.locked, "success": False, @@ -329,7 +329,7 @@ def delete_block_view(request, block_id): def print_block_rosters_view(request, block_id): if "schact_id" in request.POST: response = HttpResponse(content_type="application/pdf") - response["Content-Disposition"] = 'inline; filename="block_{}_rosters.pdf"'.format(block_id) + response["Content-Disposition"] = f'inline; filename="block_{block_id}_rosters.pdf"' sched_act_ids = request.POST.getlist("schact_id") pdf_buffer = generate_roster_pdf(sched_act_ids) @@ -340,7 +340,7 @@ def print_block_rosters_view(request, block_id): try: block = EighthBlock.objects.get(id=block_id) schacts = EighthScheduledActivity.objects.filter(block=block) - schacts = sorted(schacts, key=lambda x: "{}".format(x.get_true_sponsors())) + schacts = sorted(schacts, key=lambda x: str(x.get_true_sponsors())) except (EighthBlock.DoesNotExist, EighthScheduledActivity.DoesNotExist) as e: raise http.Http404 from e context = {"eighthblock": block, "admin_page_title": "Choose activities to print", "schacts": schacts} diff --git a/intranet/apps/eighth/views/admin/groups.py b/intranet/apps/eighth/views/admin/groups.py index 201254cc6eb..aa10e828be0 100644 --- a/intranet/apps/eighth/views/admin/groups.py +++ b/intranet/apps/eighth/views/admin/groups.py @@ -70,7 +70,7 @@ def edit_group_view(request, group_id): group.user_set.remove(u) group.save() invalidate_obj(group) - messages.success(request, "Successfully deleted {} members of the group.".format(num)) + messages.success(request, f"Successfully deleted {num} members of the group.") return redirect("eighth_admin_edit_group", group.id) form = GroupForm(request.POST, instance=group) if form.is_valid(): @@ -276,15 +276,15 @@ def upload_group_members_view(request, group_id): for uid in userids: user = get_user_model().objects.get(id=uid) if user is None: - messages.error(request, "User with ID {} does not exist".format(uid)) + messages.error(request, f"User with ID {uid} does not exist") elif user.groups.filter(id=group.id).exists(): - messages.warning(request, "User {} is already in group".format(user.username)) + messages.warning(request, f"User {user.username} is already in group") else: user.groups.add(group) user.save() num_added += 1 invalidate_obj(group) - messages.success(request, "{} added to group {}".format(num_added, group)) + messages.success(request, f"{num_added} added to group {group}") return redirect("eighth_admin_edit_group", group.id) elif "import_group" in request.POST: try: @@ -295,19 +295,19 @@ def upload_group_members_view(request, group_id): if "import_confirm" in request.POST: for member in import_group.user_set.all(): if member.groups.filter(id=group.id).exists(): - messages.warning(request, "User {} is already in group".format(member.username)) + messages.warning(request, f"User {member.username} is already in group") else: member.groups.add(group) member.save() num_users += 1 invalidate_obj(group) - messages.success(request, "Added {} users from {} to {}".format(num_users, import_group, group)) + messages.success(request, f"Added {num_users} users from {import_group} to {group}") return redirect("eighth_admin_edit_group", group.id) return render( request, "eighth/admin/upload_group.html", { - "admin_page_title": "Import Group Members: {}".format(group), + "admin_page_title": f"Import Group Members: {group}", "stage": "import_confirm", "group": group, "import_group": import_group, @@ -319,7 +319,7 @@ def upload_group_members_view(request, group_id): form = UploadGroupForm() all_groups = Group.objects.order_by("name") context = { - "admin_page_title": "Upload/Import Group Members: {}".format(group), + "admin_page_title": f"Upload/Import Group Members: {group}", "form": form, "stage": stage, "data": data, @@ -368,7 +368,7 @@ def download_group_csv_view(request, group_id): raise http.Http404 from e response = http.HttpResponse(content_type="text/csv") - response["Content-Disposition"] = 'attachment; filename="{}.csv"'.format(group.name) + response["Content-Disposition"] = f'attachment; filename="{group.name}.csv"' writer = csv.writer(response) writer.writerow(["Last Name", "First Name", "Student ID", "Grade", "Email"]) @@ -585,18 +585,16 @@ def done(self, form_list, **kwargs): except EighthScheduledActivity.DoesNotExist as e: raise http.Http404 from e - args = "" - for said in schact_ids: - args += "&schact={}".format(said) + args = "".join(f"&schact={said}" for said in schact_ids) if "group_id" in kwargs: gid = kwargs["group_id"] - args += "&group={}".format(gid) + args += f"&group={gid}" if self.request.resolver_match.url_name == "eighth_admin_distribute_unsigned": - args += "&unsigned=1&block={}".format(block.id) + args += f"&unsigned=1&block={block.id}" - return redirect("/eighth/admin/groups/distribute_action?{}".format(args)) + return redirect(f"/eighth/admin/groups/distribute_action?{args}") eighth_admin_distribute_group = eighth_admin_required(EighthAdminDistributeGroupWizard.as_view(EighthAdminDistributeGroupWizard.FORMS)) @@ -615,7 +613,7 @@ def eighth_admin_distribute_action(request): sid = int(item[6:]) schact = EighthScheduledActivity.objects.get(id=sid) except EighthScheduledActivity.DoesNotExist: - messages.error(request, "ScheduledActivity does not exist with id {}".format(sid)) + messages.error(request, f"ScheduledActivity does not exist with id {sid}") userids = request.POST.getlist(item) activity_user_map[schact] = userids @@ -641,7 +639,7 @@ def eighth_admin_distribute_action(request): changes += 1 schact.add_user(get_user_model().objects.get(id=int(uid)), request=request, force=True, no_after_deadline=True) - messages.success(request, "Successfully completed {} activity signups.".format(changes)) + messages.success(request, f"Successfully completed {changes} activity signups.") return redirect("eighth_admin_dashboard") elif "schact" in request.GET: @@ -680,13 +678,13 @@ def eighth_admin_distribute_action(request): users = users[0: int(request.GET.get("limit"))] # Sort by last name - users = sorted(list(users), key=lambda x: x.last_name) + users = sorted(users, key=lambda x: x.last_name) # Sticky check sticky_users_and_activities = {} for user in users: sticky_activity_signup = EighthSignup.objects.filter( - user=user, scheduled_activity__block=block if users_type == "unsigned" else schacts[0].block + user=user, scheduled_activity__block=block if users_type == "unsigned" else schacts[0].block # pylint: disable=used-before-assignment ).filter(Q(scheduled_activity__activity__sticky=True) | Q(scheduled_activity__sticky=True)) if sticky_activity_signup.exists(): sticky_users_and_activities[user] = sticky_activity_signup[0].scheduled_activity @@ -732,7 +730,7 @@ def add_member_to_group_view(request, group_id): user.groups.add(group) user.save() if len(user_objects) < 25: - next_url += "added={}&".format(user.id) + next_url += f"added={user.id}&" invalidate_obj(group) messages.success(request, "Successfully added {} user{} to the group.".format(len(user_objects), "s" if len(user_objects) != 1 else "")) return redirect(next_url) @@ -746,7 +744,7 @@ def add_member_to_group_view(request, group_id): if not from_sid.groups.filter(id=group.id).exists(): from_sid.groups.add(group) from_sid.save() - messages.success(request, 'Successfully added user "{}" to the group.'.format(from_sid.full_name)) + messages.success(request, f'Successfully added user "{from_sid.full_name}" to the group.') return redirect(next_url + "?added=" + str(from_sid.id)) errors, results = get_search_results(query) @@ -790,7 +788,7 @@ def remove_member_from_group_view(request, group_id, user_id): group.user_set.remove(user) group.save() invalidate_obj(group) - messages.success(request, 'Successfully removed user "{}" from the group.'.format(user.full_name)) + messages.success(request, f'Successfully removed user "{user.full_name}" from the group.') return redirect(next_url) diff --git a/intranet/apps/eighth/views/admin/hybrid.py b/intranet/apps/eighth/views/admin/hybrid.py index cf39a8427dc..14d063b3eb5 100644 --- a/intranet/apps/eighth/views/admin/hybrid.py +++ b/intranet/apps/eighth/views/admin/hybrid.py @@ -25,7 +25,7 @@ def activities_without_attendance_view(request): eighthscheduledactivity__in=EighthScheduledActivity.objects.filter(activity__name="z - Hybrid Sticky") ).filter(date__gte=get_start_date(request)): blocks_set.add((str(b.date), b.block_letter[0])) - blocks = sorted(list(blocks_set)) + blocks = sorted(blocks_set) block_id = request.GET.get("block", None) block = None @@ -62,10 +62,10 @@ def activities_without_attendance_view(request): logger.debug(zero_students) if signups.count() == 0: zero_students.update(attendance_taken=True) - messages.success(request, "Took attendance for {} empty activities.".format(zero_students.count())) + messages.success(request, f"Took attendance for {zero_students.count()} empty activities.") else: - messages.error(request, "Apparently there were actually {} signups. Maybe one is no longer empty?".format(signups.count())) - return redirect("/eighth/admin/hybrid/no_attendance?block={},{}".format(block_id[0], block_id[1])) + messages.error(request, f"Apparently there were actually {signups.count()} signups. Maybe one is no longer empty?") + return redirect(f"/eighth/admin/hybrid/no_attendance?block={block_id[0]},{block_id[1]}") if request.POST.get("take_attendance_cancelled", False) is not False: cancelled = scheduled_activities.filter(cancelled=True) @@ -74,10 +74,8 @@ def activities_without_attendance_view(request): logger.debug(signups) signups.update(was_absent=True) cancelled.update(attendance_taken=True) - messages.success( - request, "Took attendance for {} cancelled activities. {} students marked absent.".format(cancelled.count(), signups.count()) - ) - return redirect("/eighth/admin/hybrid/no_attendance?block={},{}".format(block_id[0], block_id[1])) + messages.success(request, f"Took attendance for {cancelled.count()} cancelled activities. {signups.count()} students marked absent.") + return redirect(f"/eighth/admin/hybrid/no_attendance?block={block_id[0]},{block_id[1]}") context["admin_page_title"] = "Hybrid Activities That Haven't Taken Attendance" return render(request, "eighth/admin/activities_without_attendance_hybrid.html", context) @@ -95,7 +93,7 @@ def list_sponsor_view(request): ) ): blocks_set.add((str(b.date), b.block_letter[0])) - blocks = sorted(list(blocks_set)) + blocks = sorted(blocks_set) if block_id is not None: try: diff --git a/intranet/apps/eighth/views/admin/maintenance.py b/intranet/apps/eighth/views/admin/maintenance.py index c3b1aa4789c..3e529cddb2a 100644 --- a/intranet/apps/eighth/views/admin/maintenance.py +++ b/intranet/apps/eighth/views/admin/maintenance.py @@ -28,7 +28,7 @@ def start_of_year_view(request): context["output"] = content.read() except Exception as e: # TODO: capture exception - context["output"] = "An error occured while running the start of year scripts!\n\n{}".format(e) + context["output"] = f"An error occurred while running the start of year scripts!\n\n{e}" context["completed"] = True return render(request, "eighth/admin/start_of_year.html", context) diff --git a/intranet/apps/eighth/views/admin/rooms.py b/intranet/apps/eighth/views/admin/rooms.py index 337861e62a3..6a57afbcf02 100644 --- a/intranet/apps/eighth/views/admin/rooms.py +++ b/intranet/apps/eighth/views/admin/rooms.py @@ -251,7 +251,7 @@ def room_utilization_action(request, start_id, end_id): else: rooms = all_rooms - sched_acts = sorted(sched_acts, key=lambda x: ("{}".format(x.block), "{}".format(x.get_true_rooms()))) + sched_acts = sorted(sched_acts, key=lambda x: (str(x.block), str(x.get_true_rooms()))) if show_all_rooms or show_available_for_eighth: used_rooms_ids = [] diff --git a/intranet/apps/eighth/views/admin/scheduling.py b/intranet/apps/eighth/views/admin/scheduling.py index e0bdc90177d..fb7f3a799ae 100644 --- a/intranet/apps/eighth/views/admin/scheduling.py +++ b/intranet/apps/eighth/views/admin/scheduling.py @@ -127,7 +127,7 @@ def schedule_activity_view(request): # EighthScheduledActivity instance. If there are students # in the activity then error out. if form["unschedule"].value() and instance.cancelled: - name = "{}".format(instance) + name = str(instance) count = instance.eighthsignup_set.count() bb_ok = True sibling = False @@ -141,13 +141,13 @@ def schedule_activity_view(request): instance.delete() if sibling: sibling.delete() - messages.success(request, "Unscheduled {}".format(name)) + messages.success(request, f"Unscheduled {name}") continue # don't run instance.save() elif count == 1: - messages.error(request, "Did not unschedule {} because there is {} student signed up.".format(name, count)) + messages.error(request, f"Did not unschedule {name} because there is {count} student signed up.") else: - messages.error(request, "Did not unschedule {} because there are {} students signed up.".format(name, count)) + messages.error(request, f"Did not unschedule {name} because there are {count} students signed up.") instance.save() messages.success(request, "Successfully updated schedule.") @@ -333,7 +333,7 @@ def done(self, form_list, **kwargs): # pylint: disable=unused-argument dest_activity = form_list[3].cleaned_data["activity"] dest_scheduled_activity = EighthScheduledActivity.objects.get(block=dest_block, activity=dest_activity) - req = "source_act={}&dest_act={}".format(source_scheduled_activity.id, dest_scheduled_activity.id) + req = f"source_act={source_scheduled_activity.id}&dest_act={dest_scheduled_activity.id}" return redirect("/eighth/admin/scheduling/transfer_students_action?" + req) @@ -374,7 +374,7 @@ def done(self, form_list, **kwargs): # pylint: disable=unused-argument source_activity = form_list[1].cleaned_data["activity"] source_scheduled_activity = EighthScheduledActivity.objects.get(block=source_block, activity=source_activity) - req = "source_act={}&dest_unsignup=1".format(source_scheduled_activity.id) + req = f"source_act={source_scheduled_activity.id}&dest_unsignup=1" return redirect("/eighth/admin/scheduling/transfer_students_action?" + req) @@ -421,7 +421,7 @@ def transfer_students_action(request): if dest_unsignup and not dest_act: source_act.eighthsignup_set.all().delete() invalidate_obj(source_act) - messages.success(request, "Successfully removed signups for {} students.".format(num)) + messages.success(request, f"Successfully removed signups for {num} students.") elif dest_act.block != source_act.block: # In order to prevent duplicate signups when transferring students between activities in different blocks, # we need to delete any `EighthSignup`s already present in the block of `dest_act` for transferred students. @@ -442,7 +442,7 @@ def transfer_students_action(request): invalidate_obj(source_act) invalidate_obj(dest_act) - messages.success(request, "Successfully transfered {} students.".format(num)) + messages.success(request, f"Successfully transferred {num} students.") if duplicate_sign_up_users: if send_emails: @@ -458,7 +458,7 @@ def transfer_students_action(request): invalidate_obj(source_act) invalidate_obj(dest_act) - messages.success(request, "Successfully transfered {} students.".format(num)) + messages.success(request, f"Successfully transferred {num} students.") return redirect("eighth_admin_dashboard") @@ -476,7 +476,7 @@ def remove_duplicates_view(request): if request.method == "POST": try: call_command("delete_duplicate_signups") - messages.success(request, "Successfully removed {} duplicate signups.".format(duplicates.count())) + messages.success(request, f"Successfully removed {duplicates.count()} duplicate signups.") except Exception as e: messages.error(request, e) return redirect("eighth_admin_dashboard") diff --git a/intranet/apps/eighth/views/admin/sponsors.py b/intranet/apps/eighth/views/admin/sponsors.py index 2d94a1dc1eb..5be9d76c973 100644 --- a/intranet/apps/eighth/views/admin/sponsors.py +++ b/intranet/apps/eighth/views/admin/sponsors.py @@ -75,7 +75,7 @@ def list_sponsor_view(request): if get_csv: response = http.HttpResponse(content_type="text/csv") block_str = "{}{}".format(block.date.strftime("%Y%m%d"), re.sub(r"\W+", "", block.block_letter)) - response["Content-Disposition"] = 'attachment; filename="sponsor_list_{}.csv"'.format(block_str) + response["Content-Disposition"] = f'attachment; filename="sponsor_list_{block_str}.csv"' writer = csv.writer(response) writer.writerow(["Sponsor", "Activity", "Room", "Eighth Contracted", "Signups", "Capacity"]) for row in context["sponsor_list"]: diff --git a/intranet/apps/eighth/views/attendance.py b/intranet/apps/eighth/views/attendance.py index de9d9094fc0..64a78a326ee 100644 --- a/intranet/apps/eighth/views/attendance.py +++ b/intranet/apps/eighth/views/attendance.py @@ -103,7 +103,10 @@ def get_form_kwargs(self, step=None): if self.request.user.is_restricted and sponsor is not None: kwargs.update({"sponsor": sponsor}) - labels = {"block": "Select a block", "activity": "Select an activity" if not block else block_title} + labels = { + "block": "Select a block", + "activity": "Select an activity" if not block else block_title, + } kwargs.update({"label": labels[step]}) @@ -159,7 +162,7 @@ def done(self, form_list, **kwargs): # pylint: disable=unused-argument try: scheduled_activity = EighthScheduledActivity.objects.get(block=block, activity=activity) except EighthScheduledActivity.DoesNotExist as e: - raise http.Http404("The scheduled activity with block {} and activity {} does not exist.".format(block, activity)) from e + raise http.Http404(f"The scheduled activity with block {block} and activity {activity} does not exist.") from e if "admin" in self.request.path: url_name = "eighth_admin_take_attendance" @@ -285,7 +288,7 @@ def take_attendance_view(request, scheduled_activity_id): scheduled_activity.save() invalidate_obj(scheduled_activity) - messages.success(request, "Attendance bit cleared for {}".format(scheduled_activity)) + messages.success(request, f"Attendance bit cleared for {scheduled_activity}") redirect_url = reverse(url_name, args=[scheduled_activity.id]) @@ -321,7 +324,7 @@ def take_attendance_view(request, scheduled_activity_id): else: present_user_ids.append(user[0]) except KeyError: - messages.info(request, "Error on line containing {}. If this line isn't blank, please contact an admin.".format(u)) + messages.info(request, f"Error on line containing {u}. If this line isn't blank, please contact an admin.") if unfound_users: messages.success( request, @@ -458,7 +461,7 @@ def take_attendance_view(request, scheduled_activity_id): row.append(member["email"]) row.append(scheduled_activity.block.locked) rooms = scheduled_activity.get_true_rooms() - row.append(", ".join(["{} ({})".format(room.name, room.capacity) for room in rooms])) + row.append(", ".join([f"{room.name} ({room.capacity})" for room in rooms])) sponsors = scheduled_activity.get_true_sponsors() row.append(" ,".join([sponsor.name for sponsor in sponsors])) row.append(scheduled_activity.attendance_taken) @@ -590,7 +593,7 @@ def generate_roster_pdf(sched_act_ids): header_data = [ [ - Paragraph("Activity ID: {}
Scheduled ID: {}
".format(sact.activity.id, sact.id), styles["Normal"]), + Paragraph(f"Activity ID: {sact.activity.id}
Scheduled ID: {sact.id}
", styles["Normal"]), Paragraph( "{}
{}
{}".format(sponsors_str, rooms_str, sact.block.date.strftime("%A, %B %-d, %Y")), styles["ActivityAttribute"] ), @@ -624,14 +627,14 @@ def generate_roster_pdf(sched_act_ids): members.append( ( member.last_name + ", " + member.first_name, - (member.student_id if member.student_id else "User {}".format(member.id)), + (member.student_id if member.student_id else f"User {member.id}"), int(member.grade) if member.grade else "?", ) ) members = sorted(members) for member_name, member_id, member_grade in members: - row = ["", "{} ({})".format(member_name, member_id), member_grade] + row = ["", f"{member_name} ({member_id})", member_grade] attendance_data.append(row) # Line commands are like this: @@ -649,14 +652,12 @@ def generate_roster_pdf(sched_act_ids): elements.append(Table(attendance_data, style=attendance_style, colWidths=[1.3 * inch, None, 0.8 * inch])) elements.append(Spacer(0, 15)) # NOTE: We should really not be writing raw HTML - instructions = """ + instructions = f""" Highlight or circle the names of students who are absent, and put an "X" next to those present.
If a student arrives and their name is not on the roster, please send them to the 8th Period Office.
If a student leaves your activity early, please make a note. Do not make any additions to the roster.
- Before leaving for the day, return the roster and any passes to 8th Period coordinator, {}'s mailbox in the - main office. For questions, please call extension 5046 or 5078. Thank you!
""".format( - escape(settings.EIGHTH_COORDINATOR_NAME) - ) + Before leaving for the day, return the roster and any passes to 8th Period coordinator, {escape(settings.EIGHTH_COORDINATOR_NAME)}'s + mailbox in the main office. For questions, please call extension 5046 or 5078. Thank you!
""" elements.append(Paragraph(instructions, styles["Normal"])) @@ -678,11 +679,10 @@ def eighth_absences_view(request, user_id=None): user = get_object_or_404(get_user_model(), id=user_id) elif "user" in request.GET and request.user.is_eighth_admin: user = get_object_or_404(get_user_model(), id=request.GET["user"]) + elif request.user.is_student: + user = request.user else: - if request.user.is_student: - user = request.user - else: - return redirect("eighth_admin_dashboard") + return redirect("eighth_admin_dashboard") absences = ( EighthSignup.objects.filter(user=user, was_absent=True, scheduled_activity__attendance_taken=True) @@ -735,7 +735,7 @@ def email_students_view(request, scheduled_activity_id): raise Http404 if request.method == "POST" and request.POST.get("body"): - subject = settings.EMAIL_SUBJECT_PREFIX + "{}: Message from {}".format(scheduled_activity, request.user.full_name) + subject = settings.EMAIL_SUBJECT_PREFIX + f"{scheduled_activity}: Message from {request.user.full_name}" if request.POST.get("subject"): subject += ": " + request.POST["subject"] diff --git a/intranet/apps/eighth/views/monitoring.py b/intranet/apps/eighth/views/monitoring.py index 070a1953f1e..d128056dc82 100644 --- a/intranet/apps/eighth/views/monitoring.py +++ b/intranet/apps/eighth/views/monitoring.py @@ -39,7 +39,7 @@ def metrics_view(request): .order_by("date", "block_letter") .nocache() ): - metrics['intranet_eighth_duplicate_signups{{block_id="{}"}}'.format(block_id)] = num_duplicates + metrics[f'intranet_eighth_duplicate_signups{{block_id="{block_id}"}}'] = num_duplicates context = {"metrics": metrics} diff --git a/intranet/apps/eighth/views/signup.py b/intranet/apps/eighth/views/signup.py index 4671ce6efb4..a06ee2be0fa 100644 --- a/intranet/apps/eighth/views/signup.py +++ b/intranet/apps/eighth/views/signup.py @@ -43,7 +43,7 @@ def eighth_signup_view(request, block_id=None): args = "" if "user" in request.GET: args = "?user={}".format(request.GET.get("user")) - return redirect("/eighth/signup/{}{}".format(block_id, args)) + return redirect(f"/eighth/signup/{block_id}{args}") if request.method == "POST": if "unsignup" in request.POST and "aid" not in request.POST: @@ -136,11 +136,10 @@ def eighth_signup_view(request, block_id=None): user = get_user_model().objects.get(id=request.GET["user"]) except (get_user_model().DoesNotExist, ValueError) as e: raise http.Http404 from e + elif request.user.is_student: + user = request.user else: - if request.user.is_student: - user = request.user - else: - return redirect("eighth_admin_dashboard") + return redirect("eighth_admin_dashboard") if block is None: try: @@ -262,28 +261,28 @@ def eighth_multi_signup_view(request): try: btxt = EighthBlock.objects.get(id=bid).short_text except EighthBlock.DoesNotExist: - return http.HttpResponse("{}: Block did not exist.".format(bid), status=403) + return http.HttpResponse(f"{bid}: Block did not exist.", status=403) except ValueError: - return http.HttpResponse("{}: Invalid block ID.".format(bid), status=403) + return http.HttpResponse(f"{bid}: Invalid block ID.", status=403) try: eighth_signup = EighthSignup.objects.get(scheduled_activity__block__id=bid, user__id=uid) success_message = eighth_signup.remove_signup(request.user, force, request.session.get("disable_waitlist_transactions", False)) except EighthSignup.DoesNotExist: status = 403 - display_messages.append("{}: Signup did not exist.".format(btxt)) + display_messages.append(f"{btxt}: Signup did not exist.") except SignupException as e: show_admin_messages = request.user.is_eighth_admin and not request.user.is_student resp = e.as_response(admin=show_admin_messages) status = 403 - display_messages.append("{}: {}".format(btxt, resp.content)) + display_messages.append(f"{btxt}: {resp.content}") except Exception: - display_messages.append("{}: Unknown error.".format(btxt)) + display_messages.append(f"{btxt}: Unknown error.") else: - display_messages.append("{}: {}".format(btxt, success_message)) + display_messages.append(f"{btxt}: {success_message}") return http.HttpResponse("\n".join(display_messages), status=status) @@ -308,14 +307,14 @@ def eighth_multi_signup_view(request): try: btxt = EighthBlock.objects.get(id=bid).short_text except EighthBlock.DoesNotExist: - return http.HttpResponse("{}: Block did not exist.".format(bid), status=403) + return http.HttpResponse(f"{bid}: Block did not exist.", status=403) try: scheduled_activity = ( EighthScheduledActivity.objects.exclude(activity__deleted=True).exclude(cancelled=True).get(block=bid, activity=aid) ) except EighthScheduledActivity.DoesNotExist: - display_messages.append("{}: Activity was not scheduled for block".format(btxt)) + display_messages.append(f"{btxt}: Activity was not scheduled for block") else: try: success_message = scheduled_activity.add_user(user, request) @@ -323,9 +322,9 @@ def eighth_multi_signup_view(request): show_admin_messages = request.user.is_eighth_admin and not request.user.is_student resp = e.as_response(admin=show_admin_messages) status = 403 - display_messages.append("{}: {}".format(btxt, resp.content)) + display_messages.append(f"{btxt}: {resp.content}") else: - display_messages.append("{}: {}".format(btxt, success_message)) + display_messages.append(f"{btxt}: {success_message}") return http.HttpResponse("
".join(display_messages), status=status) else: @@ -334,11 +333,10 @@ def eighth_multi_signup_view(request): user = get_user_model().objects.get(id=request.GET["user"]) except (get_user_model().DoesNotExist, ValueError) as e: raise http.Http404 from e + elif request.user.is_student: + user = request.user else: - if request.user.is_student: - user = request.user - else: - return redirect("eighth_admin_dashboard") + return redirect("eighth_admin_dashboard") block_ids = list(filter(None, request.GET.getlist("block"))) try: diff --git a/intranet/apps/emailfwd/models.py b/intranet/apps/emailfwd/models.py index b7a91a42038..8cd87a7ddc0 100644 --- a/intranet/apps/emailfwd/models.py +++ b/intranet/apps/emailfwd/models.py @@ -7,4 +7,4 @@ class SeniorEmailForward(models.Model): email = models.EmailField() def __str__(self): - return "{}".format(self.user) + return str(self.user) diff --git a/intranet/apps/emailfwd/views.py b/intranet/apps/emailfwd/views.py index 5bbbcd05d92..aaaac66e405 100644 --- a/intranet/apps/emailfwd/views.py +++ b/intranet/apps/emailfwd/views.py @@ -36,9 +36,8 @@ def senior_email_forward_view(request): return redirect("index") else: messages.error(request, "Error adding forwarding address.") + elif forward: + form = SeniorEmailForwardForm(instance=forward) else: - if forward: - form = SeniorEmailForwardForm(instance=forward) - else: - form = SeniorEmailForwardForm() + form = SeniorEmailForwardForm() return render(request, "emailfwd/senior_forward.html", {"form": form, "forward": forward}) diff --git a/intranet/apps/emerg/views.py b/intranet/apps/emerg/views.py index 31d96da593b..666f0f6ccc0 100644 --- a/intranet/apps/emerg/views.py +++ b/intranet/apps/emerg/views.py @@ -34,7 +34,7 @@ def check_emerg(): timeout = settings.EMERGENCY_TIMEOUT try: - r = requests.get("{}?{}".format(fcps_page, int(time.time() // 60)), timeout=timeout) + r = requests.get(f"{fcps_page}?{int(time.time() // 60)}", timeout=timeout) except requests.exceptions.Timeout: return False, None @@ -128,7 +128,7 @@ def get_emerg(): Timeout defined in settings.CACHE_AGE["emerg"] """ - key = "emerg:{}".format(timezone.localdate()) + key = f"emerg:{timezone.localdate()}" cached = cache.get(key) if cached: return cached @@ -153,6 +153,6 @@ def update_emerg_cache(*, custom_logger=None) -> None: messages relating to the cache update. """ - key = "emerg:{}".format(timezone.localdate()) + key = f"emerg:{timezone.localdate()}" result = get_emerg_result(custom_logger=custom_logger) cache.set(key, result, timeout=settings.CACHE_AGE["emerg"]) diff --git a/intranet/apps/enrichment/models.py b/intranet/apps/enrichment/models.py index 4400e8d4bbd..5f660706f9e 100644 --- a/intranet/apps/enrichment/models.py +++ b/intranet/apps/enrichment/models.py @@ -109,7 +109,7 @@ def is_too_early_to_signup(self): return (now < (activity_date - presign_period), activity_date - presign_period) def __str__(self): - return "{} - {}".format(self.title, self.time) + return f"{self.title} - {self.time}" class Meta: ordering = ["time"] diff --git a/intranet/apps/events/models.py b/intranet/apps/events/models.py index 7c86ffe2220..5172ec3cb24 100644 --- a/intranet/apps/events/models.py +++ b/intranet/apps/events/models.py @@ -97,7 +97,7 @@ class EventUserMap(models.Model): users_hidden = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, related_name="events_hidden") def __str__(self): - return "UserMap: {}".format(self.event.title) + return f"UserMap: {self.event.title}" class Event(models.Model): @@ -217,9 +217,9 @@ def happened(self): def __str__(self): if not self.approved: - return "UNAPPROVED - {} - {}".format(self.title, self.time) + return f"UNAPPROVED - {self.title} - {self.time}" else: - return "{} - {}".format(self.title, self.time) + return f"{self.title} - {self.time}" class Meta: ordering = ["time"] diff --git a/intranet/apps/events/notifications.py b/intranet/apps/events/notifications.py index 689c95598b0..9bba8c07236 100644 --- a/intranet/apps/events/notifications.py +++ b/intranet/apps/events/notifications.py @@ -5,7 +5,7 @@ def event_approval_request(request, event): - subject = "Event Approval Request from {}".format(event.user) + subject = f"Event Approval Request from {event.user}" emails = [settings.APPROVAL_EMAIL] base_url = request.build_absolute_uri(reverse("index")) diff --git a/intranet/apps/events/tests.py b/intranet/apps/events/tests.py index 2e6d4ca8073..60f6d94af89 100644 --- a/intranet/apps/events/tests.py +++ b/intranet/apps/events/tests.py @@ -38,11 +38,11 @@ def test_event_model(self): self.assertTrue(EventUserMap.objects.filter(event=event).count(), 1) self.assertEqual(event.user_map, user_map) - self.assertEqual(str(event.user_map), "UserMap: {}".format(event.title)) + self.assertEqual(str(event.user_map), f"UserMap: {event.title}") - self.assertEqual("UNAPPROVED - {} - {}".format(unapproved_event.title, unapproved_event.time), str(unapproved_event)) + self.assertEqual(f"UNAPPROVED - {unapproved_event.title} - {unapproved_event.time}", str(unapproved_event)) - self.assertEqual("{} - {}".format(event.title, event.time), str(event)) + self.assertEqual(f"{event.title} - {event.time}", str(event)) next_event = self.create_random_event(user, time=timezone.now() + timezone.timedelta(days=15)) prev_event = self.create_random_event(user, time=timezone.now() - timezone.timedelta(days=15)) @@ -116,7 +116,7 @@ def test_view_roster(self): # Test with a few attendees num_users = 5 for i in range(num_users): - user = get_user_model().objects.create(username="2020jdoe{}".format(i)) + user = get_user_model().objects.create(username=f"2020jdoe{i}") event.attending.add(user) event.save() diff --git a/intranet/apps/events/views.py b/intranet/apps/events/views.py index 02bc50916a0..af71741cc51 100644 --- a/intranet/apps/events/views.py +++ b/intranet/apps/events/views.py @@ -148,7 +148,7 @@ def events_view(request): event.approved = True event.approved_by = request.user event.save() - messages.success(request, "Approved event {}".format(event)) + messages.success(request, f"Approved event {event}") logger.info("Admin %s approved event: %s (%s)", request.user, event, event.id) else: raise http.Http404 @@ -161,7 +161,7 @@ def events_view(request): event.rejected = True event.rejected_by = request.user event.save() - messages.success(request, "Rejected event {}".format(event)) + messages.success(request, f"Rejected event {event}") logger.info("Admin %s rejected event: %s (%s)", request.user, event, event.id) else: raise http.Http404 diff --git a/intranet/apps/feedback/models.py b/intranet/apps/feedback/models.py index 868a2f1961f..08762d24b15 100644 --- a/intranet/apps/feedback/models.py +++ b/intranet/apps/feedback/models.py @@ -11,4 +11,4 @@ class Meta: ordering = ["-date"] def __str__(self): - return "{} - {}".format(self.user, self.date) + return f"{self.user} - {self.date}" diff --git a/intranet/apps/feedback/views.py b/intranet/apps/feedback/views.py index 28070fbd7c8..f0db23569b6 100644 --- a/intranet/apps/feedback/views.py +++ b/intranet/apps/feedback/views.py @@ -14,14 +14,12 @@ def send_feedback_email(request, data): data["user"] = request.user - email = request.user.tj_email if request.user.is_authenticated else "unknown-{}@tjhsst.edu".format(request.user) + email = request.user.tj_email if request.user.is_authenticated else f"unknown-{request.user}@tjhsst.edu" data["email"] = email data["remote_ip"] = request.META["HTTP_X_REAL_IP"] if "HTTP_X_REAL_IP" in request.META else request.META.get("REMOTE_ADDR", "") data["user_agent"] = request.META.get("HTTP_USER_AGENT") - headers = {"Reply-To": "{}; {}".format(email, settings.FEEDBACK_EMAIL)} - email_send_task.delay( - "feedback/email.txt", "feedback/email.html", data, "Feedback from {}".format(request.user), [settings.FEEDBACK_EMAIL], headers - ) + headers = {"Reply-To": f"{email}; {settings.FEEDBACK_EMAIL}"} + email_send_task.delay("feedback/email.txt", "feedback/email.html", data, f"Feedback from {request.user}", [settings.FEEDBACK_EMAIL], headers) @login_required diff --git a/intranet/apps/files/forms.py b/intranet/apps/files/forms.py index 542849e01c7..226e0b6b56a 100644 --- a/intranet/apps/files/forms.py +++ b/intranet/apps/files/forms.py @@ -11,8 +11,8 @@ def validate_size(self): filesize = self.file.__sizeof__() if filesize > settings.FILES_MAX_UPLOAD_SIZE: raise forms.ValidationError( - "The file uploaded is above the maximum upload size ({}MB). " - "Use a desktop client to upload this file.".format(settings.FILES_MAX_UPLOAD_SIZE / 1024 / 1024) + f"The file uploaded is above the maximum upload size ({settings.FILES_MAX_UPLOAD_SIZE / 1024 / 1024}MB). " + "Use a desktop client to upload this file." ) file = forms.FileField(validators=[validate_size]) diff --git a/intranet/apps/files/models.py b/intranet/apps/files/models.py index d5110650647..950ec95d495 100644 --- a/intranet/apps/files/models.py +++ b/intranet/apps/files/models.py @@ -54,7 +54,7 @@ def visible_to(self, user): return self in Host.objects.visible_to_user(user) def __str__(self): - return "{} ({})".format(self.name, self.code) + return f"{self.name} ({self.code})" class Meta: ordering = ["-linux", "name"] diff --git a/intranet/apps/files/views.py b/intranet/apps/files/views.py index a8f5cf3666e..9453d1a37a9 100644 --- a/intranet/apps/files/views.py +++ b/intranet/apps/files/views.py @@ -125,7 +125,7 @@ def windows_dir_format(host_dir, user): return host_dir if grade in range(9, 13): - win_path = "/{}/".format(user.username) + win_path = f"/{user.username}/" else: win_path = "" return host_dir.replace("{win}", win_path) @@ -174,13 +174,13 @@ def files_type(request, fstype=None): try: sftp.chdir(host_dir) except exceptions as e: - if "NoSuchFile" in "{}".format(e): + if "NoSuchFile" in str(e): host_dir = "/" try: sftp.chdir(host_dir) except exceptions as e2: messages.error(request, e) - messages.error(request, "Root directory: {}".format(e2)) + messages.error(request, f"Root directory: {e2}") return redirect("files") else: messages.error(request, "Unable to access home folder -- showing root directory instead.") @@ -209,26 +209,26 @@ def can_access_path(fsdir): try: fstat = sftp.stat(filepath) except exceptions as e: - messages.error(request, "Unable to access {}: {}".format(filebase, e)) - return redirect("/files/{}?dir={}".format(fstype, os.path.dirname(filepath))) + messages.error(request, f"Unable to access {filebase}: {e}") + return redirect(f"/files/{fstype}?dir={os.path.dirname(filepath)}") if fstat.st_size > settings.FILES_MAX_DOWNLOAD_SIZE: messages.error(request, "Too large to download (>200MB)") - return redirect("/files/{}?dir={}".format(fstype, os.path.dirname(filepath))) + return redirect(f"/files/{fstype}?dir={os.path.dirname(filepath)}") - with tempfile.TemporaryFile(prefix="ion_filecenter_{}_{}".format(request.user.username, filebase_escaped)) as tmpfile: + with tempfile.TemporaryFile(prefix=f"ion_filecenter_{request.user.username}_{filebase_escaped}") as tmpfile: try: sftp.getfo(filepath, tmpfile) except exceptions as e: messages.error(request, e) - return redirect("/files/{}?dir={}".format(fstype, os.path.dirname(filepath))) + return redirect(f"/files/{fstype}?dir={os.path.dirname(filepath)}") content_len = tmpfile.tell() tmpfile.seek(0) chunk_size = 8192 response = StreamingHttpResponse(FileWrapper(tmpfile, chunk_size), content_type="application/octet-stream") response["Content-Length"] = content_len - response["Content-Disposition"] = "attachment; filename={}".format(filebase_escaped) + response["Content-Disposition"] = f"attachment; filename={filebase_escaped}" return response fsdir = request.GET.get("dir") @@ -242,15 +242,15 @@ def can_access_path(fsdir): return redirect("files") else: messages.error(request, "Access to the path you provided is restricted.") - return redirect("/files/{}/?dir={}".format(fstype, default_dir)) + return redirect(f"/files/{fstype}/?dir={default_dir}") if "zip" in request.GET: dirbase_escaped = os.path.basename(fsdir) dirbase_escaped = slugify(dirbase_escaped) - with tempfile.TemporaryDirectory( - prefix="ion_filecenter_{}_{}_zip".format(request.user.username, dirbase_escaped) - ) as tmpdir, tempfile.TemporaryFile(prefix="ion_filecenter_{}_{}".format(request.user.username, dirbase_escaped)) as tmpfile: + with tempfile.TemporaryDirectory(prefix=f"ion_filecenter_{request.user.username}_{dirbase_escaped}_zip") as tmpdir, tempfile.TemporaryFile( + prefix=f"ion_filecenter_{request.user.username}_{dirbase_escaped}" + ) as tmpfile: remote_directories = [fsdir] totalsize = 0 while remote_directories: @@ -275,7 +275,7 @@ def can_access_path(fsdir): totalsize += fstat.st_size if totalsize > settings.FILES_MAX_DOWNLOAD_SIZE: messages.error(request, "Too large to download (>200MB)") - return redirect("/files/{}?dir={}".format(fstype, os.path.dirname(fsdir))) + return redirect(f"/files/{fstype}?dir={os.path.dirname(fsdir)}") try: localpath = os.path.join(tmpdir, os.path.relpath(rd, fsdir)) @@ -410,11 +410,11 @@ def can_access_path(fsdir): fstat = sftp.stat(filepath) is_directory = stat.S_ISDIR(fstat.st_mode) except exceptions as e: - messages.error(request, "Unable to access {}: {}".format(filepath, e)) - return redirect("/files/{}?dir={}".format(fstype, os.path.dirname(filepath))) + messages.error(request, f"Unable to access {filepath}: {e}") + return redirect(f"/files/{fstype}?dir={os.path.dirname(filepath)}") else: - messages.error(request, "Unable to access {}".format(filepath)) - return redirect("/files/{}?dir={}".format(fstype, os.path.dirname(filepath))) + messages.error(request, f"Unable to access {filepath}") + return redirect(f"/files/{fstype}?dir={os.path.dirname(filepath)}") def rmtree(sftp, path): for f in sftp.listdir_attr(path): @@ -435,8 +435,8 @@ def rmtree(sftp, path): except PermissionError: messages.error(request, "You are not allowed to delete this " + ("folder" if is_directory else "file") + "!") except exceptions as e: - messages.error(request, "{}".format(e)) - return redirect("/files/{}?dir={}".format(fstype, os.path.dirname(filepath))) + messages.error(request, str(e)) + return redirect(f"/files/{fstype}?dir={os.path.dirname(filepath)}") context = {"host": host, "remote_dir": os.path.dirname(filepath), "is_directory": is_directory} return render(request, "files/delete.html", context) @@ -498,10 +498,10 @@ def can_access_path(fsdir): fsdir = normpath(fsdir) if not can_access_path(fsdir): messages.error(request, "Access to the path you provided is restricted.") - return redirect("/files/{}?dir={}".format(fstype, default_dir)) + return redirect(f"/files/{fstype}?dir={default_dir}") handle_file_upload(request.FILES["file"], fsdir, sftp, request) - return redirect("/files/{}?dir={}".format(fstype, fsdir)) + return redirect(f"/files/{fstype}?dir={fsdir}") else: form = UploadFileForm() context = {"host": host, "remote_dir": fsdir, "form": form, "max_upload_mb": (settings.FILES_MAX_UPLOAD_SIZE / 1024 / 1024)} @@ -515,12 +515,12 @@ def handle_file_upload(file, fsdir, sftp, request=None): messages.error(request, e) return - remote_path = "{}/{}".format(fsdir, file.name) + remote_path = f"{fsdir}/{file.name}" try: sftp.putfo(file, remote_path) except exceptions as e: # Remote path does not exist - messages.error(request, "Unable to upload: {}".format(e)) + messages.error(request, f"Unable to upload: {e}") return - messages.success(request, "Uploaded {} to {}".format(file.name, fsdir)) + messages.success(request, f"Uploaded {file.name} to {fsdir}") diff --git a/intranet/apps/groups/models.py b/intranet/apps/groups/models.py index d459ddc9698..14e1928529c 100644 --- a/intranet/apps/groups/models.py +++ b/intranet/apps/groups/models.py @@ -65,4 +65,4 @@ class GroupProperties(models.Model): student_visible = models.BooleanField(default=False) def __str__(self): - return "{}".format(self.group) + return str(self.group) diff --git a/intranet/apps/itemreg/models.py b/intranet/apps/itemreg/models.py index a438908a6b6..cc24998fc77 100644 --- a/intranet/apps/itemreg/models.py +++ b/intranet/apps/itemreg/models.py @@ -24,7 +24,7 @@ class CalculatorRegistration(models.Model): added = models.DateTimeField(auto_now_add=True) def __str__(self): - return "{}'s {}".format(self.user.full_name, self.get_calc_type_display()) # get_FIELD_display() is defined by models.Model + return f"{self.user.full_name}'s {self.get_calc_type_display()}" # get_FIELD_display() is defined by models.Model class ComputerRegistration(models.Model): @@ -59,10 +59,10 @@ def computer_name(self) -> str: A nicely formatted description of the computer. """ - return '{}" {} {}'.format(self.screen_size, self.get_manufacturer_display(), self.model) + return f'{self.screen_size}" {self.get_manufacturer_display()} {self.model}' def __str__(self): - return "{}'s {}".format(self.user.full_name, self.computer_name) + return f"{self.user.full_name}'s {self.computer_name}" class PhoneRegistration(models.Model): @@ -92,7 +92,7 @@ def phone_name(self) -> str: A nicely formatted description of the phone. """ - return "{} {}".format(self.get_manufacturer_display(), self.model) + return f"{self.get_manufacturer_display()} {self.model}" def __str__(self): - return "{}'s {}".format(self.user.full_name, self.model) + return f"{self.user.full_name}'s {self.model}" diff --git a/intranet/apps/itemreg/templatetags/texthighlight.py b/intranet/apps/itemreg/templatetags/texthighlight.py index e09152e6acf..e7751d0c5f6 100644 --- a/intranet/apps/itemreg/templatetags/texthighlight.py +++ b/intranet/apps/itemreg/templatetags/texthighlight.py @@ -10,6 +10,6 @@ def highlight(str1, str2): str2 = str2[0] if str1 and str2 and isinstance(str2, str): - return str1.replace(str2, "{}".format(str2)) + return str1.replace(str2, f"{str2}") else: return str1 diff --git a/intranet/apps/itemreg/views.py b/intranet/apps/itemreg/views.py index b3e58356e0c..daf811b1411 100644 --- a/intranet/apps/itemreg/views.py +++ b/intranet/apps/itemreg/views.py @@ -110,10 +110,10 @@ def register_view(request, item_type): obj = form.save() obj.user = request.user obj.save() - messages.success(request, "Successfully added {}.".format(item_type)) + messages.success(request, f"Successfully added {item_type}.") return redirect("itemreg") else: - messages.error(request, "Error adding {}.".format(item_type)) + messages.error(request, f"Error adding {item_type}.") else: form = form_class() @@ -131,7 +131,7 @@ def register_delete_view(request, item_type, item_id): if request.method == "POST" and "confirm" in request.POST: obj.delete() - messages.success(request, "Deleted {}".format(item_type)) + messages.success(request, f"Deleted {item_type}") return redirect("itemreg") return render(request, "itemreg/register_delete.html", {"type": item_type, "obj": obj}) diff --git a/intranet/apps/logs/models.py b/intranet/apps/logs/models.py index 7caf87491a6..a262e9470ed 100644 --- a/intranet/apps/logs/models.py +++ b/intranet/apps/logs/models.py @@ -33,7 +33,7 @@ def request_json_obj(self): return json.loads(self.request) def __str__(self): - return f'{self.timestamp.astimezone(settings.PYTZ_TIME_ZONE).strftime("%b %d %Y %H:%M:%S")} - {self.username} - {self.ip} - {self.method} "{self.path}"' # noqa: E501 pylint: disable=line-too-long + return f'{self.timestamp.astimezone(settings.PYTZ_TIME_ZONE).strftime("%b %d %Y %H:%M:%S")} - {self.username} - {self.ip} - {self.method} "{self.path}"' # pylint: disable=line-too-long # noqa: E501 class Meta: ordering = ["-timestamp"] diff --git a/intranet/apps/logs/views.py b/intranet/apps/logs/views.py index 5390dd57995..ad16148f637 100644 --- a/intranet/apps/logs/views.py +++ b/intranet/apps/logs/views.py @@ -114,7 +114,7 @@ def logs_view(request): if network.num_addresses > 2**16: messages.error(request, f"Subnet too large: {ip}.") else: - ips |= set(str(ip) for ip in network.hosts()) + ips |= {str(ip) for ip in network.hosts()} except ValueError: messages.error(request, f"Invalid IP network: {ip}") diff --git a/intranet/apps/lostfound/models.py b/intranet/apps/lostfound/models.py index e5eaad1f3dd..05ddaee9b66 100644 --- a/intranet/apps/lostfound/models.py +++ b/intranet/apps/lostfound/models.py @@ -11,7 +11,7 @@ class LostItem(models.Model): found = models.BooleanField(default=False) def __str__(self): - return "{}".format(self.title) + return str(self.title) class Meta: ordering = ["-added"] @@ -26,7 +26,7 @@ class FoundItem(models.Model): retrieved = models.BooleanField(default=False) def __str__(self): - return "{}".format(self.title) + return str(self.title) class Meta: ordering = ["-added"] diff --git a/intranet/apps/notifications/emails.py b/intranet/apps/notifications/emails.py index 87a8d959845..dd0ff536271 100644 --- a/intranet/apps/notifications/emails.py +++ b/intranet/apps/notifications/emails.py @@ -24,7 +24,7 @@ def email_send( Args: text_template: URL to a Django template for the text email's contents - html_template: URL to a Django tempalte for the HTML email's contents + html_template: URL to a Django template for the HTML email's contents data: The context to pass to the templates subject: The subject of the email emails: The addresses to send the email to @@ -60,7 +60,7 @@ def email_send( msg.attach_alternative(html_content, "text/html") email_msg.append(msg) - logger.debug("Emailing %s to %s in %d seperate emails", subject, emails, len(email_msg)) + logger.debug("Emailing %s to %s in %d separate emails", subject, emails, len(email_msg)) # We only want to actually send emails if we are in production or explicitly force sending. if settings.PRODUCTION or settings.FORCE_EMAIL_SEND: diff --git a/intranet/apps/notifications/models.py b/intranet/apps/notifications/models.py index a1f8f3b8cc2..b5251ff2841 100644 --- a/intranet/apps/notifications/models.py +++ b/intranet/apps/notifications/models.py @@ -18,7 +18,7 @@ def gcm_token_sha256(self): return hashlib.sha256(self.gcm_token.encode()).hexdigest() def __str__(self): - return "{}".format(self.user) + return str(self.user) class GCMNotification(models.Model): @@ -31,7 +31,7 @@ class GCMNotification(models.Model): user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) def __str__(self): - return "{} at {}".format(self.multicast_id, self.time) + return f"{self.multicast_id} at {self.time}" @property def data(self): diff --git a/intranet/apps/notifications/views.py b/intranet/apps/notifications/views.py index 37428a09db0..33a19300fbc 100644 --- a/intranet/apps/notifications/views.py +++ b/intranet/apps/notifications/views.py @@ -141,7 +141,7 @@ def gcm_post(nc_users, data, user=None, request=None): else: fail_ids.append(ncid) - headers = {"Content-Type": "application/json", "project_id": settings.GCM_PROJECT_ID, "Authorization": "key={}".format(settings.GCM_AUTH_KEY)} + headers = {"Content-Type": "application/json", "project_id": settings.GCM_PROJECT_ID, "Authorization": f"key={settings.GCM_AUTH_KEY}"} postdata = {"registration_ids": reg_ids, "data": data} postjson = json.dumps(postdata) req = requests.post("https://android.googleapis.com/gcm/send", headers=headers, data=postjson, timeout=15) @@ -193,7 +193,7 @@ def gcm_post_view(request): if post: messages.success(request, "Delivered message: {} success, {} failure".format(post["success"], post["failure"])) else: - messages.error(request, "Failed. {}".format(reqtext)) + messages.error(request, f"Failed. {reqtext}") return render(request, "notifications/gcm_post.html", context) diff --git a/intranet/apps/oauth/admin.py b/intranet/apps/oauth/admin.py index 4385b1ad13f..ff2f11d4213 100644 --- a/intranet/apps/oauth/admin.py +++ b/intranet/apps/oauth/admin.py @@ -62,8 +62,8 @@ def sanction_applications(self, request, queryset): self.message_user( request, ngettext( - f"Succesfully sanctioned {updated} application.", - f"Succesfully sanctioned {updated} applications.", + f"Successfully sanctioned {updated} application.", + f"Successfully sanctioned {updated} applications.", updated, ), messages.SUCCESS, diff --git a/intranet/apps/parking/admin.py b/intranet/apps/parking/admin.py index 31177abd61d..67d2d3e37aa 100644 --- a/intranet/apps/parking/admin.py +++ b/intranet/apps/parking/admin.py @@ -23,14 +23,14 @@ class ParkingAdmin(admin.ModelAdmin): def get_user(self, obj): u = obj.user - return mark_safe("{} {} ({})
{} absences".format(u.first_name, u.last_name, u.grade.number, u.absence_count())) + return mark_safe(f"{u.first_name} {u.last_name} ({u.grade.number})
{u.absence_count()} absences") get_user.short_description = "User" # type: ignore def get_joint_user(self, obj): u = obj.joint_user if u: - return mark_safe("{} {} ({})
{} absences".format(u.first_name, u.last_name, u.grade.number, u.absence_count())) + return mark_safe(f"{u.first_name} {u.last_name} ({u.grade.number})
{u.absence_count()} absences") return "n/a" get_joint_user.short_description = "Joint User" # type: ignore diff --git a/intranet/apps/parking/models.py b/intranet/apps/parking/models.py index 29cac177859..c30afc11b36 100644 --- a/intranet/apps/parking/models.py +++ b/intranet/apps/parking/models.py @@ -12,7 +12,7 @@ class CarApplication(models.Model): updated = models.DateTimeField(auto_now_add=True) def __str__(self): - return "{} {} {} ({})".format(self.year, self.make, self.model, self.license_plate) + return f"{self.year} {self.make} {self.model} ({self.license_plate})" class ParkingApplication(models.Model): @@ -25,7 +25,7 @@ class ParkingApplication(models.Model): updated = models.DateTimeField(auto_now_add=True) def __str__(self): - s = "Parking Application for {}".format(self.user) + s = f"Parking Application for {self.user}" if self.joint_user: - s += " and jointly {}".format(self.joint_user) + s += f" and jointly {self.joint_user}" return s diff --git a/intranet/apps/parking/views.py b/intranet/apps/parking/views.py index b43e68a77ec..7d6c0497a6e 100644 --- a/intranet/apps/parking/views.py +++ b/intranet/apps/parking/views.py @@ -72,11 +72,10 @@ def parking_form_view(request): return redirect("parking_form") else: messages.error(request, "Error adding.") + elif app: + form = ParkingApplicationForm(instance=app) else: - if app: - form = ParkingApplicationForm(instance=app) - else: - form = ParkingApplicationForm() + form = ParkingApplicationForm() return render(request, "parking/form.html", {"form": form, "app": app, "in_joint": in_joint}) @@ -128,11 +127,10 @@ def parking_car_view(request): return redirect("parking_form") else: messages.error(request, "Error adding.") + elif car: + form = CarApplicationForm(instance=car) else: - if car: - form = CarApplicationForm(instance=car) - else: - form = CarApplicationForm() + form = CarApplicationForm() return render(request, "parking/car.html", {"form": form, "car": car, "app": app}) diff --git a/intranet/apps/polls/models.py b/intranet/apps/polls/models.py index 52021eec7fa..aa57ca09d4e 100644 --- a/intranet/apps/polls/models.py +++ b/intranet/apps/polls/models.py @@ -104,13 +104,13 @@ def get_num_eligible_voters(self): return get_user_model().objects.exclude(user_type="service").count() def get_percentage_voted(self, voted, able): - return "{:.1%}".format(0 if able == 0 else voted / able) + return f"{0 if able == 0 else voted / able:.1%}" def get_voted_string(self): users_voted = len(self.get_users_voted()) users_able = self.get_num_eligible_voters() percent = self.get_percentage_voted(users_voted, users_able) - return "{} out of {} ({}) eligible users voted in this poll.".format(users_voted, users_able, percent) + return f"{users_voted} out of {users_able} ({percent}) eligible users voted in this poll." def has_user_voted(self, user): return Answer.objects.filter(question__in=self.question_set.all(), user=user).count() == self.question_set.count() @@ -216,7 +216,7 @@ def get_total_votes(self): def __str__(self): # return "{} + #{} ('{}')".format(self.poll, self.num, self.trunc_question()) - return "Question #{}: '{}'".format(self.num, self.trunc_question()) + return f"Question #{self.num}: '{self.trunc_question()}'" @classmethod def get_question_types(cls): @@ -261,7 +261,7 @@ def display_name(self): def __str__(self): # return "{} + O#{}('{}')".format(self.question, self.num, self.trunc_info()) - return "Option #{}: {}".format(self.num, self.trunc_info()) + return f"Option #{self.num}: {self.trunc_info()}" class Meta: ordering = ["num"] @@ -285,13 +285,13 @@ def display_votes(self): def __str__(self): if self.choice: - return "{} {}".format(self.user, self.choice) + return f"{self.user} {self.choice}" elif self.answer: - return "{} {}".format(self.user, self.answer[:25]) + return f"{self.user} {self.answer[:25]}" elif self.clear_vote: - return "{} Clear".format(self.user) + return f"{self.user} Clear" else: - return "{} None".format(self.user) + return f"{self.user} None" class AnswerVote(models.Model): # record of total selection of a given answer choice diff --git a/intranet/apps/preferences/tests.py b/intranet/apps/preferences/tests.py index 902f94ef413..a3a8ac52b30 100644 --- a/intranet/apps/preferences/tests.py +++ b/intranet/apps/preferences/tests.py @@ -189,8 +189,8 @@ def test_privacy_options_view(self): self.assertIn(f"{permission}-{permission_type}", options.keys()) self.assertFalse(options[f"{permission}-{permission_type}"]) else: - self.assertIn(f"{permission}", options.keys()) - self.assertFalse(options[f"{permission}"]) + self.assertIn(str(permission), options.keys()) + self.assertFalse(options[str(permission)]) # Now, test loading the view user = self.login() diff --git a/intranet/apps/preferences/views.py b/intranet/apps/preferences/views.py index 0a148f7803d..6740926eeee 100644 --- a/intranet/apps/preferences/views.py +++ b/intranet/apps/preferences/views.py @@ -43,7 +43,7 @@ def get_personal_info(user): # personal_info["phone_{}".format(i)] = user.phones.all()[i] for i in range(num_emails): - personal_info["email_{}".format(i)] = user.emails.all()[i] + personal_info[f"email_{i}"] = user.emails.all()[i] # for i in range(num_websites): # personal_info["website_{}".format(i)] = user.websites.all()[i] @@ -135,7 +135,7 @@ def get_privacy_options(user): for ptype in user.permissions: for field in user.permissions[ptype]: if ptype == "self": - privacy_options["{}-{}".format(field, ptype)] = user.permissions[ptype][field] + privacy_options[f"{field}-{ptype}"] = user.permissions[ptype][field] else: privacy_options[field] = user.permissions[ptype][field] @@ -171,7 +171,7 @@ def save_privacy_options(request, user): if not success: raise Exception("You cannot override the parent field.") except Exception as e: - messages.error(request, "Unable to set field {} with value {}: {}".format(field, fields[field], e)) + messages.error(request, f"Unable to set field {field} with value {fields[field]}: {e}") logger.debug("Unable to set field %s with value %s: %s", field, fields[field], e) else: messages.success( @@ -256,7 +256,7 @@ def save_bus_route(request, user): ), ) else: - messages.success(request, "Cleared field {}".format(field)) + messages.success(request, f"Cleared field {field}") except TypeError: pass return bus_route_form diff --git a/intranet/apps/printing/forms.py b/intranet/apps/printing/forms.py index 70a532258d4..deddafa04d0 100644 --- a/intranet/apps/printing/forms.py +++ b/intranet/apps/printing/forms.py @@ -23,9 +23,7 @@ def __init__(self, *args, **kwargs): def validate_size(self): filesize = self.file.__sizeof__() if filesize > settings.FILES_MAX_UPLOAD_SIZE: - raise forms.ValidationError( - "The file uploaded is above the maximum upload size ({}MB). ".format(settings.FILES_MAX_UPLOAD_SIZE / 1024 / 1024) - ) + raise forms.ValidationError(f"The file uploaded is above the maximum upload size ({settings.FILES_MAX_UPLOAD_SIZE / 1024 / 1024}MB). ") file = forms.FileField(validators=[validate_size]) printer = forms.ChoiceField() diff --git a/intranet/apps/printing/magic_files/msooxml b/intranet/apps/printing/magic_files/msooxml index 194cf53fe24..a67d89c7784 100644 --- a/intranet/apps/printing/magic_files/msooxml +++ b/intranet/apps/printing/magic_files/msooxml @@ -36,10 +36,10 @@ # and check the subdirectory name to determine which type of OOXML # file we have. Correct the mimetype with the registered ones: # https://technet.microsoft.com/en-us/library/cc179224.aspx ->>>>&26 use msooxml +>>>>&26 use msooxml >>>>&26 default x # OpenOffice/Libreoffice orders ZIP entry differently, so check the 4th file >>>>>&26 search/6000 PK\003\004 ->>>>>>&26 use msooxml +>>>>>>&26 use msooxml >>>>>>&26 default x Microsoft OOXML >>>>>&26 default x Microsoft OOXML diff --git a/intranet/apps/printing/models.py b/intranet/apps/printing/models.py index 641f38163d6..2cf44d9388c 100644 --- a/intranet/apps/printing/models.py +++ b/intranet/apps/printing/models.py @@ -30,4 +30,4 @@ class PrintJob(models.Model): fit = models.BooleanField(default=False, verbose_name="Fit-to-page") def __str__(self): - return "{} by {} to {}".format(self.file, self.user, self.printer) + return f"{self.file} by {self.user} to {self.printer}" diff --git a/intranet/apps/printing/views.py b/intranet/apps/printing/views.py index 4604319c2c4..d2a90f29426 100644 --- a/intranet/apps/printing/views.py +++ b/intranet/apps/printing/views.py @@ -72,17 +72,15 @@ def get_printers() -> Dict[str, str]: # Record the name of the printer so when we parse the rest of the # extended description we know which printer it's referring to. last_name = name - else: - # If we've seen a line with the name of a printer before - if last_name is not None: - match = DESCRIPTION_LINE_RE.match(line) - if match is not None: - # Pull out the description - description = match.group(1) - # And make sure we don't set an empty description - if description: - printers[last_name] = description - last_name = None + elif last_name is not None: + match = DESCRIPTION_LINE_RE.match(line) + if match is not None: + # Pull out the description + description = match.group(1) + # And make sure we don't set an empty description + if description: + printers[last_name] = description + last_name = None cache.set(key, printers, timeout=settings.CACHE_AGE["printers_list"]) return printers @@ -120,7 +118,7 @@ def convert_soffice(tmpfile_name: str) -> Optional[str]: def convert_pdf(tmpfile_name: str, cmdname: str = "ps2pdf") -> Optional[str]: - new_name = "{}.pdf".format(tmpfile_name) + new_name = f"{tmpfile_name}.pdf" try: output = subprocess.check_output([cmdname, tmpfile_name, new_name], stderr=subprocess.STDOUT, universal_newlines=True) except subprocess.CalledProcessError as e: @@ -184,7 +182,7 @@ def get_mimetype(tmpfile_name: str) -> str: def convert_file(tmpfile_name: str, orig_fname: str) -> Optional[str]: detected = get_mimetype(tmpfile_name) - add_breadcrumb(category="printing", message="Detected file type {}".format(detected), level="debug") + add_breadcrumb(category="printing", message=f"Detected file type {detected}", level="debug") no_conversion = ["application/pdf", "text/plain"] soffice_convert = [ @@ -206,11 +204,11 @@ def convert_file(tmpfile_name: str, orig_fname: str) -> Optional[str]: if orig_fname.endswith((".doc", ".docx")): raise InvalidInputPrintingError( - "Invalid file type {}
Note: It looks like you are trying to print a Word document. Word documents don't always print correctly, so we " - "recommend that you convert to a PDF before printing.".format(detected) + f"Invalid file type {detected}
Note: It looks like you are trying to print a Word document. " + "Word documents don't always print correctly, so we recommend that you convert to a PDF before printing." ) - raise InvalidInputPrintingError("Invalid file type {}".format(detected)) + raise InvalidInputPrintingError(f"Invalid file type {detected}") def check_page_range(page_range: str, max_pages: int) -> Optional[int]: @@ -287,7 +285,7 @@ def print_job(obj: PrintJob, do_print: bool = True): # This needs to be a set because we may add duplicate entries to it delete_filenames = set() try: - tmpfile_fd, tmpfile_name = tempfile.mkstemp(prefix="ion_print_{}_{}".format(obj.user.username, filebase_escaped), text=False) + tmpfile_fd, tmpfile_name = tempfile.mkstemp(prefix=f"ion_print_{obj.user.username}_{filebase_escaped}", text=False) delete_filenames.add(tmpfile_name) # This implicitly closes tmpfile_fd when it's done writing @@ -317,7 +315,7 @@ def print_job(obj: PrintJob, do_print: bool = True): line_width = 81 lines_per_page = 62 - with open(final_filename, "r", encoding="utf-8") as f: + with open(final_filename, encoding="utf-8") as f: # Every newline-terminated line of the file will take up 1 printed line, plus an # additional printed line for each time it wraps. # We subtract 1 from the line length because having exactly `line_width` characters @@ -331,7 +329,7 @@ def print_job(obj: PrintJob, do_print: bool = True): else: num_pages = get_numpages(final_filename) if num_pages < 0: - raise Exception("Could not get number of pages in {}".format(filebase)) + raise Exception(f"Could not get number of pages in {filebase}") if re.search(r"\d\s+\d", obj.page_range) is not None: # Make sure that when removing spaces in the page range we don't accidentally combine two numbers @@ -351,20 +349,18 @@ def print_job(obj: PrintJob, do_print: bool = True): raise InvalidInputPrintingError("You specified an invalid page range.") elif range_count > settings.PRINTING_PAGES_LIMIT: raise InvalidInputPrintingError( - "You specified a range of {} pages. You may only print up to {} pages using this tool.".format( - range_count, settings.PRINTING_PAGES_LIMIT - ) + f"You specified a range of {range_count} pages. You may only print up to {settings.PRINTING_PAGES_LIMIT} pages using this tool." ) elif num_pages > settings.PRINTING_PAGES_LIMIT: raise InvalidInputPrintingError( - "This file contains {} pages. You may only print up to {} pages using this tool.".format(num_pages, settings.PRINTING_PAGES_LIMIT) + f"This file contains {num_pages} pages. You may only print up to {settings.PRINTING_PAGES_LIMIT} pages using this tool." ) if do_print: args = ["lpr", "-P", printer, final_filename] if obj.page_range: - args.extend(["-o", "page-ranges={}".format(obj.page_range)]) + args.extend(["-o", f"page-ranges={obj.page_range}"]) if obj.duplex: args.extend(["-o", "sides=two-sided-long-edge"]) @@ -395,7 +391,7 @@ def print_job(obj: PrintJob, do_print: bool = True): raise Exception(e.output.strip()) from e logger.error("Could not run lpr (returned %d): %s", e.returncode, e.output.strip()) - raise Exception("An error occurred while printing your file: {}".format(e.output.strip())) from e + raise Exception(f"An error occurred while printing your file: {e.output.strip()}") from e obj.printed = True obj.save() diff --git a/intranet/apps/schedule/api.py b/intranet/apps/schedule/api.py index defb220748c..0bb6a640442 100644 --- a/intranet/apps/schedule/api.py +++ b/intranet/apps/schedule/api.py @@ -43,4 +43,4 @@ def get_object(self): day.pk = -1 # The URL will be null unless pk is set return day except exceptions.ValidationError as e: - raise serializers.ValidationError(e) + raise serializers.ValidationError(e) from e diff --git a/intranet/apps/schedule/models.py b/intranet/apps/schedule/models.py index 3368da8ebca..95cfd3a2794 100644 --- a/intranet/apps/schedule/models.py +++ b/intranet/apps/schedule/models.py @@ -10,12 +10,12 @@ class Time(models.Model): def __str__(self): minute = "0" + str(self.minute) if self.minute < 10 else self.minute - return "{}:{}".format(self.hour, minute) + return f"{self.hour}:{minute}" def str_12_hr(self): hour = self.hour if self.hour <= 12 else (self.hour - 12) minute = "0" + str(self.minute) if self.minute < 10 else self.minute - return "{}:{}".format(hour, minute) + return f"{hour}:{minute}" def date_obj(self, date): return datetime.datetime(date.year, date.month, date.day, self.hour, self.minute) @@ -32,7 +32,7 @@ class Block(models.Model): order = models.IntegerField(default=0) def __str__(self): - return "{}: {} - {}".format(self.name, self.start, self.end) + return f"{self.name}: {self.start} - {self.end}" class Meta: unique_together = ("order", "name", "start", "end") @@ -70,9 +70,9 @@ def class_name(self): t = "anchor" if self.special: - return "day-type-{} day-special".format(t) + return f"day-type-{t} day-special" else: - return "day-type-{}".format(t) + return f"day-type-{t}" @property def start_time(self) -> Time: @@ -145,7 +145,7 @@ def end_time(self): return self.day_type.end_time def __str__(self): - return "{}: {}".format(str(self.date), self.day_type) + return f"{self.date}: {self.day_type}" class Meta: ordering = ("date",) diff --git a/intranet/apps/schedule/notifications.py b/intranet/apps/schedule/notifications.py index cdcf1573d77..583d45567fc 100644 --- a/intranet/apps/schedule/notifications.py +++ b/intranet/apps/schedule/notifications.py @@ -16,9 +16,9 @@ def period_start_end_data(request): blocks = ctx["sched_ctx"]["blocks"] point, block = at_period_point(blocks) if point == 1: - return {"title": "{} has started".format(block.name), "text": "{}".format(block)} + return {"title": f"{block.name} has started", "text": str(block)} elif point == 2: - return {"title": "{} has ended".format(block.name), "text": "{}".format(block)} + return {"title": f"{block.name} has ended", "text": str(block)} else: return None diff --git a/intranet/apps/schedule/views.py b/intranet/apps/schedule/views.py index c1b56f5e4fd..0704f1e3796 100644 --- a/intranet/apps/schedule/views.py +++ b/intranet/apps/schedule/views.py @@ -59,7 +59,7 @@ def schedule_context(request=None, date=None, use_cache=True, show_tomorrow=True date += timedelta(days=1) date_fmt = date_format(date) - key = "bell_schedule:{}".format(date_fmt) + key = f"bell_schedule:{date_fmt}" cached = cache.get(key) if cached and use_cache: return cached @@ -340,7 +340,7 @@ def admin_add_view(request): messages.success(request, "{} is now a {}".format(date, form.cleaned_data["day_type"])) return redirect("schedule_admin") else: - messages.success(request, "{} has no schedule assigned".format(date)) + messages.success(request, f"{date} has no schedule assigned") return redirect("schedule_admin") else: form = DayForm() @@ -399,9 +399,9 @@ def admin_daytype_view(request, daytype_id=None): if "delete" in request.POST: daytype = get_object_or_404(DayType, id=daytype_id) - name = "{}".format(daytype) + name = str(daytype) daytype.delete() - messages.success(request, "Deleted {}".format(name)) + messages.success(request, f"Deleted {name}") return redirect("schedule_admin") if daytype_id: @@ -436,7 +436,7 @@ def admin_daytype_view(request, daytype_id=None): else: dayobj.day_type = model dayobj.save() - messages.success(request, "{} is now a {}".format(dayobj.date, dayobj.day_type)) + messages.success(request, f"{dayobj.date} is now a {dayobj.day_type}") messages.success(request, "Successfully {} Day Type.".format("modified" if daytype_id else "added")) return redirect("schedule_daytype", model.id) diff --git a/intranet/apps/search/utils.py b/intranet/apps/search/utils.py index 4dcaf92b4c7..a61a8342174 100644 --- a/intranet/apps/search/utils.py +++ b/intranet/apps/search/utils.py @@ -4,7 +4,7 @@ def normalize_query(query_string, findterms=re.compile(r'"([^"]+)"|(\S+)').findall, normspace=re.compile(r"\s{2,}").sub): - """Splits the query string in individual keywords, getting rid of unecessary spaces + """Splits the query string in individual keywords, getting rid of unnecessary spaces and grouping quoted words together. Example: diff --git a/intranet/apps/search/views.py b/intranet/apps/search/views.py index a357eeb82ae..3c0468d48c8 100644 --- a/intranet/apps/search/views.py +++ b/intranet/apps/search/views.py @@ -25,7 +25,7 @@ def query(q, admin=False): if is_entirely_digit(q): results = list(get_user_model().objects.exclude_from_search().filter(Q(student_id=q) | Q(id=q))) elif ":" in q or ">" in q or "<" in q or "=" in q: - # A mapping between search keys and LDAP entires + # A mapping between search keys and LDAP entries map_attrs = { "firstname": ("first_name", "nickname"), "first": ("first_name", "nickname"), @@ -93,14 +93,14 @@ def query(q, admin=False): if exact: # No implied wildcard for cat in default_categories: - sub_query |= Q(**{"{}__iexact".format(cat): p}) + sub_query |= Q(**{f"{cat}__iexact": p}) else: # Search firstname, lastname, uid, nickname (+ middlename if admin) with # implied wildcard at beginning and end of the search # string for cat in default_categories: - sub_query |= Q(**{"{}__icontains".format(cat): p}) + sub_query |= Q(**{f"{cat}__icontains": p}) search_query &= sub_query continue # skip rest of processing @@ -114,7 +114,7 @@ def query(q, admin=False): # fix grade, because LDAP only stores graduation year if cat == "grade" and is_entirely_digit(val): - val = "{}".format(Grade.year_from_grade(int(val))) + val = str(Grade.year_from_grade(int(val))) elif cat == "grade" and val == "staff": cat = "type" val = "teacher" @@ -140,7 +140,7 @@ def query(q, admin=False): # for each of the possible LDAP fields, add to the search query sub_query = Q(pk=-1) for attr in attrs: - sub_query |= Q(**{"{}{}".format(attr, sep): val}) + sub_query |= Q(**{f"{attr}{sep}": val}) search_query &= sub_query results = list(get_user_model().objects.exclude_from_search().filter(search_query)) @@ -163,7 +163,7 @@ def query(q, admin=False): if exact: # No implied wildcard for cat in default_categories: - sub_query |= Q(**{"{}__iexact".format(cat): p}) + sub_query |= Q(**{f"{cat}__iexact": p}) else: if p.endswith("*"): p = p[:-1] @@ -172,7 +172,7 @@ def query(q, admin=False): # Search for first, last, middle, nickname uid, with implied # wildcard at beginning and end for cat in default_categories: - sub_query |= Q(**{"{}__icontains".format(cat): p}) + sub_query |= Q(**{f"{cat}__icontains": p}) search_query &= sub_query results = list(get_user_model().objects.exclude_from_search().filter(search_query)) @@ -201,12 +201,12 @@ def get_search_results(q, admin=False): def do_activities_search(q): filter_query = get_query(q, ["name", "description"]) - entires = EighthActivity.objects.filter(filter_query).order_by("name") - final_entires = [] - for e in entires: + entries = EighthActivity.objects.filter(filter_query).order_by("name") + final_entries = [] + for e in entries: if e.is_active: - final_entires.append(e) - return final_entires + final_entries.append(e) + return final_entries def do_courses_search(q): @@ -216,32 +216,32 @@ def do_courses_search(q): def do_announcements_search(q, user): filter_query = get_query(q, ["title", "content"]) - entires = AnnouncementManager().visible_to_user(user).filter(filter_query).order_by("title") - final_entires = [] - for e in entires: + entries = AnnouncementManager().visible_to_user(user).filter(filter_query).order_by("title") + final_entries = [] + for e in entries: if e.is_this_year: - final_entires.append(e) - return final_entires + final_entries.append(e) + return final_entries def do_events_search(q): filter_query = get_query(q, ["title", "description"]) - entires = Event.objects.filter(filter_query).order_by("title") - final_entires = [] - for e in entires: + entries = Event.objects.filter(filter_query).order_by("title") + final_entries = [] + for e in entries: if e.is_this_year: - final_entires.append(e) - return final_entires + final_entries.append(e) + return final_entries def do_enrichment_search(q): filter_query = get_query(q, ["title", "description"]) - entires = EnrichmentActivity.objects.filter(filter_query).order_by("title") - final_entires = [] - for e in entires: + entries = EnrichmentActivity.objects.filter(filter_query).order_by("title") + final_entries = [] + for e in entries: if e.is_this_year: - final_entires.append(e) - return final_entires + final_entries.append(e) + return final_entries @login_required diff --git a/intranet/apps/seniors/management/commands/import_colleges.py b/intranet/apps/seniors/management/commands/import_colleges.py index f2f501829d2..33ec5bc863f 100644 --- a/intranet/apps/seniors/management/commands/import_colleges.py +++ b/intranet/apps/seniors/management/commands/import_colleges.py @@ -9,10 +9,10 @@ class Command(BaseCommand): help = "Import colleges from ceeb.csv file" def handle(self, *args, **options): - with open("ceeb.csv", "r", encoding="utf-8") as f: + with open("ceeb.csv", encoding="utf-8") as f: reader = csv.reader(f) for row in reader: ceeb, name, city, state = row - College.objects.create(ceeb=ceeb, name=("{} - {}, {}".format(name, city, state)).title()) + College.objects.create(ceeb=ceeb, name=(f"{name} - {city}, {state}").title()) # custom additions College.objects.create(ceeb=-1, name="University of Swamp (Harvard of the South) - The South") diff --git a/intranet/apps/seniors/models.py b/intranet/apps/seniors/models.py index 923028d94ee..00cbb349cf1 100644 --- a/intranet/apps/seniors/models.py +++ b/intranet/apps/seniors/models.py @@ -9,7 +9,7 @@ class College(models.Model): ceeb = models.IntegerField(unique=True) def __str__(self): - return "{} ({})".format(self.name, self.ceeb) + return f"{self.name} ({self.ceeb})" class Meta: ordering = ["name"] @@ -129,7 +129,7 @@ class Senior(models.Model): major_sure = models.BooleanField(default=False) def __str__(self): - return "{}".format(self.user) + return str(self.user) class Meta: ordering = ["user"] diff --git a/intranet/apps/seniors/tests.py b/intranet/apps/seniors/tests.py index 343914947e7..c4a53ee60bc 100644 --- a/intranet/apps/seniors/tests.py +++ b/intranet/apps/seniors/tests.py @@ -122,6 +122,6 @@ def test_import_colleges(self): with patch("intranet.apps.seniors.management.commands.import_colleges.open", mock_open(read_data=file_contents)) as m: call_command("import_colleges") - m.assert_called_with("ceeb.csv", "r", encoding="utf-8") + m.assert_called_with("ceeb.csv", encoding="utf-8") self.assertEqual(1, College.objects.filter(ceeb=1234, name="Computer Systems Lab University - Alexandria, Virginia").count()) self.assertEqual(1, College.objects.filter(ceeb=1235, name="Other University - Anytown, Virginia").count()) diff --git a/intranet/apps/seniors/views.py b/intranet/apps/seniors/views.py index 13765eaaf7a..7e55b4fe772 100644 --- a/intranet/apps/seniors/views.py +++ b/intranet/apps/seniors/views.py @@ -50,11 +50,10 @@ def seniors_add_view(request): obj.save() messages.success(request, "Your information was {}".format("modified" if senior else "added")) return redirect("seniors") + elif senior: + form = SeniorForm(instance=senior) else: - if senior: - form = SeniorForm(instance=senior) - else: - form = SeniorForm() + form = SeniorForm() context = {"form": form, "senior": senior} diff --git a/intranet/apps/signage/consumers.py b/intranet/apps/signage/consumers.py index 532eb469303..3598715d60b 100644 --- a/intranet/apps/signage/consumers.py +++ b/intranet/apps/signage/consumers.py @@ -50,7 +50,7 @@ def disconnect(self, code: int) -> None: if not self.connected: return - self.connnected = False + self.connected = False if self.sign_obj is not None: self.sign_obj.refresh_from_db() diff --git a/intranet/apps/signage/pages.py b/intranet/apps/signage/pages.py index b022ee9df07..a35581ab2b0 100644 --- a/intranet/apps/signage/pages.py +++ b/intranet/apps/signage/pages.py @@ -9,7 +9,7 @@ def hello_world(page, sign, request): - return {"message": "{} from {} says Hello".format(page.name, sign.name)} + return {"message": f"{page.name} from {sign.name} says Hello"} def announcements(page, sign, request): # pylint: disable=unused-argument diff --git a/intranet/apps/signage/templatetags/signage.py b/intranet/apps/signage/templatetags/signage.py index 6ea8622f45b..7f1b81c3bbb 100644 --- a/intranet/apps/signage/templatetags/signage.py +++ b/intranet/apps/signage/templatetags/signage.py @@ -11,7 +11,7 @@ def render_page(page, page_args): """Renders the template at page.template""" print(page_args) template_name = page.template if page.template else page.name - template_fname = "signage/pages/{}.html".format(template_name) + template_fname = f"signage/pages/{template_name}.html" if page.function: context_method = getattr(pages, page.function) else: diff --git a/intranet/apps/signage/views.py b/intranet/apps/signage/views.py index 9efe1ecf775..077981b8273 100644 --- a/intranet/apps/signage/views.py +++ b/intranet/apps/signage/views.py @@ -156,7 +156,7 @@ def prometheus_metrics(request): metrics = {"intranet_signage_num_signs_online": Sign.objects.filter_online().count()} for sign in Sign.objects.all(): - metrics['intranet_signage_sign_is_online{{display="{}"}}'.format(sign.display)] = int(not sign.is_offline) + metrics[f'intranet_signage_sign_is_online{{display="{sign.display}"}}'] = int(not sign.is_offline) context = {"metrics": metrics} diff --git a/intranet/apps/templatetags/dates.py b/intranet/apps/templatetags/dates.py index a02ace8df78..076213f5103 100644 --- a/intranet/apps/templatetags/dates.py +++ b/intranet/apps/templatetags/dates.py @@ -39,14 +39,14 @@ def fuzzy_date(date): if minutes <= 1: return "moments ago" elif minutes < 60: - return "{} minutes ago".format(int(seconds // 60)) + return f"{int(seconds // 60)} minutes ago" elif hours < 24: hrs = int(diff.seconds // (60 * 60)) return "{} hour{} ago".format(hrs, "s" if hrs != 1 else "") elif diff.days == 1: return "yesterday" elif diff.days < 7: - return "{} days ago".format(int(seconds // (60 * 60 * 24))) + return f"{int(seconds // (60 * 60 * 24))} days ago" elif diff.days < 14: return date.strftime("last %A") else: @@ -61,14 +61,14 @@ def fuzzy_date(date): if minutes <= 1: return "moments ago" elif minutes < 60: - return "in {} minutes".format(int(seconds // 60)) + return f"in {int(seconds // 60)} minutes" elif hours < 24: hrs = int(diff.seconds // (60 * 60)) return "in {} hour{}".format(hrs, "s" if hrs != 1 else "") elif diff.days == 1: return "tomorrow" elif diff.days < 7: - return "in {} days".format(int(seconds // (60 * 60 * 24))) + return f"in {int(seconds // (60 * 60 * 24))} days" elif diff.days < 14: return date.strftime("next %A") else: diff --git a/intranet/apps/templatetags/forms.py b/intranet/apps/templatetags/forms.py index 0a23340fde6..56efe5f9f22 100644 --- a/intranet/apps/templatetags/forms.py +++ b/intranet/apps/templatetags/forms.py @@ -29,6 +29,6 @@ def field_array_size(field): prefix = m.groups()[0] count = 0 for field_name in field.form.fields.keys(): - if re.match(r"^{}_(\d+)$".format(prefix), field_name): + if re.match(rf"^{prefix}_(\d+)$", field_name): count += 1 return count diff --git a/intranet/apps/users/api.py b/intranet/apps/users/api.py index 6954c7aa9f3..0550a25ad14 100644 --- a/intranet/apps/users/api.py +++ b/intranet/apps/users/api.py @@ -1,4 +1,3 @@ -import io import os from rest_framework import generics @@ -92,7 +91,7 @@ def retrieve(self, request, *args, **kwargs): binary = user.default_photo if binary is None: default_image_path = os.path.join(settings.PROJECT_ROOT, "static/img/default_profile_pic.png") - with io.open(default_image_path, mode="rb") as f: + with open(default_image_path, mode="rb") as f: binary = f.read() return Response(binary, content_type="image/jpeg") diff --git a/intranet/apps/users/forms.py b/intranet/apps/users/forms.py index 6a82e220e83..a7ad762554e 100644 --- a/intranet/apps/users/forms.py +++ b/intranet/apps/users/forms.py @@ -69,7 +69,7 @@ def __init__(self, *args, **kwargs): def label_from_instance(self, obj): name = obj.last_first_initial - return "{} ({})".format(name, obj.username) if self.show_username else name + return f"{name} ({obj.username})" if self.show_username else name class AddressForm(forms.ModelForm): diff --git a/intranet/apps/users/management/commands/import_groups.py b/intranet/apps/users/management/commands/import_groups.py index 81b8e8652c4..5ceef8a9c60 100644 --- a/intranet/apps/users/management/commands/import_groups.py +++ b/intranet/apps/users/management/commands/import_groups.py @@ -11,7 +11,7 @@ class Command(BaseCommand): def handle(self, *args, **options): mappings = {} - with open("groups_name.csv", "r", encoding="utf-8") as namesopen: + with open("groups_name.csv", encoding="utf-8") as namesopen: names = csv.reader(namesopen) for gid, gname, _ in names: gname = gname.replace("eighth_", "") @@ -20,17 +20,17 @@ def handle(self, *args, **options): mappings[gid] = gexist[0] else: ngrp = Group.objects.create(name=gname) - self.stdout.write("Created group {} with new id {}, old id {}".format(gname, ngrp.id, gid)) + self.stdout.write(f"Created group {gname} with new id {ngrp.id}, old id {gid}") mappings[gid] = ngrp - self.stdout.write("{}".format(mappings)) - with open("groups_static.csv", "r", encoding="utf-8") as staticopen: + self.stdout.write(str(mappings)) + with open("groups_static.csv", encoding="utf-8") as staticopen: static = csv.reader(staticopen) for uid, gid in static: try: usrobj = get_user_model().objects.get(id=uid) except get_user_model().DoesNotExist: - self.stdout.write("UID {} doesn't exist, for adding to group {}".format(uid, gid)) + self.stdout.write(f"UID {uid} doesn't exist, for adding to group {gid}") else: grp = mappings[gid] usrobj.groups.add(grp) diff --git a/intranet/apps/users/models.py b/intranet/apps/users/models.py index 054c07b94ce..a7df5c7b1bf 100644 --- a/intranet/apps/users/models.py +++ b/intranet/apps/users/models.py @@ -170,7 +170,8 @@ def get_approve_announcements_users_sorted(self) -> "QuerySet[User]": # noqa return self.get_approve_announcements_users().order_by("last_name", "first_name") def exclude_from_search( - self, existing_queryset: Optional[Union[Collection["User"], QuerySet]] = None # pylint: disable=unsubscriptable-object + self, + existing_queryset: Optional[Union[Collection["User"], QuerySet]] = None, # pylint: disable=unsubscriptable-object ) -> Union[Collection["User"], QuerySet]: # pylint: disable=unsubscriptable-object if existing_queryset is None: existing_queryset = self @@ -899,11 +900,7 @@ def has_senior(self) -> bool: current user. """ - try: - self.senior - except AttributeError: - return False - return True + return hasattr(self, "senior") @property def is_attendance_taker(self) -> bool: @@ -1260,7 +1257,7 @@ def attribute_is_public(self, permission: str) -> bool: PERMISSIONS_NAMES = { - prefix: [name[len(prefix) + 1:] for name in dir(UserProperties) if name.startswith(prefix + "_")] for prefix in ["self", "parent"] + prefix: [name[len(prefix) + 1:] for name in dir(UserProperties) if name.startswith(prefix + "_")] for prefix in ["self", "parent"] # noqa: E501 } @@ -1417,7 +1414,7 @@ def __init__(self, graduation_year): self._number = get_senior_graduation_year() - int(graduation_year) + 12 if 9 <= self._number <= 12: - self._name = [elem[1] for elem in GRADE_NUMBERS if elem[0] == self._number][0] + self._name = next(elem[1] for elem in GRADE_NUMBERS if elem[0] == self._number) else: self._name = "graduate" diff --git a/intranet/apps/users/tests.py b/intranet/apps/users/tests.py index 87dda652c46..8a0e4ddfc3d 100644 --- a/intranet/apps/users/tests.py +++ b/intranet/apps/users/tests.py @@ -1,5 +1,4 @@ import datetime -import io import os from oauth2_provider.models import AccessToken, get_application_model @@ -25,13 +24,13 @@ def setUp(self): def create_schedule_test(self): for i in range(9): - course = Course.objects.create(name="Test Course {}".format(i), course_id="1111{}".format(i)) + course = Course.objects.create(name=f"Test Course {i}", course_id=f"1111{i}") for pd in range(1, 8): - Section.objects.create(course=course, room="Room {}".format(i), period=pd, section_id="{}-{}".format(course.course_id, pd), sem="F") + Section.objects.create(course=course, room=f"Room {i}", period=pd, section_id=f"{course.course_id}-{pd}", sem="F") def test_section_course_attributes(self): course = Course.objects.first() - self.assertEqual(str(course), "{} ({})".format(course.name, course.course_id)) + self.assertEqual(str(course), f"{course.name} ({course.course_id})") section = Section.objects.first() self.assertEqual(str(section), "{} ({}) - {} Pd. {}".format(section.course.name, section.section_id, "Unknown", section.period)) @@ -258,7 +257,7 @@ def test_notification_email(self): self.assertEqual(user.primary_email, None) self.assertFalse(user.emails.exists()) - self.assertEqual(user.tj_email, "{}@tjhsst.edu".format(user.username)) + self.assertEqual(user.tj_email, f"{user.username}@tjhsst.edu") self.assertEqual(user.notification_email, user.tj_email) email = Email.objects.create(user=user, address="test@example.com") @@ -437,16 +436,16 @@ def test_tj_email_non_tj_email(self): self.assertEqual(user.primary_email, None) self.assertFalse(user.emails.exists()) - self.assertEqual(user.tj_email, "{}@tjhsst.edu".format(user.username)) + self.assertEqual(user.tj_email, f"{user.username}@tjhsst.edu") self.assertEqual(user.non_tj_email, None) personal_email = Email.objects.create(user=user, address="abc@example.com") - self.assertEqual(user.tj_email, "{}@tjhsst.edu".format(user.username)) + self.assertEqual(user.tj_email, f"{user.username}@tjhsst.edu") self.assertEqual(user.non_tj_email, personal_email.address) user.user_type = "teacher" user.save() - self.assertEqual(user.tj_email, "{}@fcps.edu".format(user.username)) + self.assertEqual(user.tj_email, f"{user.username}@fcps.edu") self.assertEqual(user.non_tj_email, personal_email.address) user.user_type = "student" user.save() @@ -529,7 +528,7 @@ def make_token(self): tok = AccessToken.objects.create( user=self.user, token="1234567890", application=self.application, scope="read write", expires=timezone.now() + datetime.timedelta(days=1) ) - self.auth = "Bearer {}".format(tok.token) # pylint: disable=attribute-defined-outside-init + self.auth = f"Bearer {tok.token}" # pylint: disable=attribute-defined-outside-init def test_get_profile_api(self): self.make_admin() @@ -545,10 +544,10 @@ def test_get_profile_api(self): # Verify that response is the same response_with_username = self.client.get( - reverse("api_user_myprofile_detail") + "?username={}".format(self.user.username), HTTP_AUTHORIZATION=self.auth + reverse("api_user_myprofile_detail") + f"?username={self.user.username}", HTTP_AUTHORIZATION=self.auth ) self.assertEqual(response_with_username.json(), response.json()) - response_with_pk = self.client.get(reverse("api_user_myprofile_detail") + "?pk={}".format(self.user.pk), HTTP_AUTHORIZATION=self.auth) + response_with_pk = self.client.get(reverse("api_user_myprofile_detail") + f"?pk={self.user.pk}", HTTP_AUTHORIZATION=self.auth) self.assertEqual(response_with_pk.json(), response.json()) def test_get_profile_picture_api(self): @@ -559,7 +558,7 @@ def test_get_profile_picture_api(self): response = self.client.get(reverse("api_user_profile_picture_default", args=[user.pk]), HTTP_AUTHORIZATION=self.auth) self.assertEqual(response.content_type, "image/jpeg") image_path = os.path.join(settings.PROJECT_ROOT, "static/img/default_profile_pic.png") - with io.open(image_path, mode="rb") as f: + with open(image_path, mode="rb") as f: self.assertEqual(response.content, f.read()) response_with_username = self.client.get( reverse("api_user_profile_picture_default_by_username", args=[user.username]), HTTP_AUTHORIZATION=self.auth diff --git a/intranet/apps/users/views.py b/intranet/apps/users/views.py index e99e7d09f95..dc4d3fff11c 100644 --- a/intranet/apps/users/views.py +++ b/intranet/apps/users/views.py @@ -138,18 +138,18 @@ def picture_view(request, user_id, year=None): data = None if data is None: - img = io.open(default_image_path, mode="rb").read() + img = open(default_image_path, mode="rb").read() else: image_buffer = io.BytesIO(data) response = HttpResponse(content_type="image/jpeg") - response["Content-Disposition"] = "filename={}_{}.jpg".format(user_id, year or preferred) + response["Content-Disposition"] = f"filename={user_id}_{year or preferred}.jpg" if img is None: try: img = image_buffer.read() except UnicodeDecodeError: - img = io.open(default_image_path, mode="rb").read() + img = open(default_image_path, mode="rb").read() image_buffer.close() response.write(img) diff --git a/intranet/settings/__init__.py b/intranet/settings/__init__.py index 545b5cc82eb..7777dddbfc7 100644 --- a/intranet/settings/__init__.py +++ b/intranet/settings/__init__.py @@ -839,7 +839,7 @@ def get_log(name): # pylint: disable=redefined-outer-name; 'name' is used as th # Already set on nginx level SECURE_BROWSER_XSS_FILTER = True -# To accomodate for the fact that nginx "swallows" https connections +# To accommodate for the fact that nginx "swallows" https connections # by forwarding to http://gunicorn # https://docs.djangoproject.com/en/dev/ref/settings/#secure-proxy-ssl-header SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") diff --git a/intranet/static/img/patterns/confectionary.png b/intranet/static/img/patterns/confectionery.png similarity index 100% rename from intranet/static/img/patterns/confectionary.png rename to intranet/static/img/patterns/confectionery.png diff --git a/intranet/static/img/patterns/dark/confectionary.png b/intranet/static/img/patterns/dark/confectionery.png similarity index 100% rename from intranet/static/img/patterns/dark/confectionary.png rename to intranet/static/img/patterns/dark/confectionery.png diff --git a/scripts/dev_autoupdate_static.sh b/scripts/dev_autoupdate_static.sh index d726d6cd852..8cf90cca895 100755 --- a/scripts/dev_autoupdate_static.sh +++ b/scripts/dev_autoupdate_static.sh @@ -10,7 +10,7 @@ cd intranet/static sass --watch css:../collected_static/css & # Everything else -inotifywait --format '%w%f %e' -rm -e modify -e create -e delete --exclude '\.scss$' . | +inotifywait --format '%w%f %e' -rm -e modify -e create -e delete --exclude '\.scss$' . | while read -r file action; do file=${file#./} # Remove leading ./ from file path if [ "$action" = "CREATE" ] || [ "$action" = "MODIFY" ]; then