Sazzadur Rahman
Sazzadur Rahman

Reputation: 2930

Why Python is adding unnecessary characters at the beginning of a file while overwriting it?

In a Django project I have created a .env file to store my application's secret credentials. And I am using console command to generating some of the credentials. Here is my initial .env file,

SECRET_KEY=CHANGE_IT
DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=database_name
DB_USERNAME=database_username
DB_PASSWORD=database_password
DB_SCHEMA=database_schema_name

And here is my generate_secret console command to overwrite the SECRET_KEY with random string,

import re
import os

from django.core.management import BaseCommand
from django.core.management.utils import get_random_secret_key


class Command(BaseCommand):
    help = ''

    def handle(self, *args, **options):
        env_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../.env'))

        self.set_secret_key(env_path, get_random_secret_key())

    @staticmethod
    def set_secret_key(env_file_path, secret_key):
        fp = open(env_file_path, 'r+')

        current_env = fp.read()
        regex = r"(SECRET_KEY=.*?)\n"

        matches = re.findall(regex, current_env, re.MULTILINE)

        updated_env = current_env.replace(matches[0], 'SECRET_KEY={}'.format(secret_key))

        fp.truncate(0)
        fp.write(updated_env)

        fp.close()

The problem is when I am running the command, it overwrites the SECRET_KEY correctly but also adding bunch of wired characters at the start of the .env file. I running on Ubuntu 18.04 operating system. Here is the .env file after running the command,

enter image description here

I am not sure why but I can not copy those wired characters, so I have attached the screenshot of it.

Upvotes: 0

Views: 87

Answers (1)

Dušan Maďar
Dušan Maďar

Reputation: 9909

Not sure why, but fp.truncate(0) seems to be the culprit (see Behaviour of truncate() method in Python for more info).

Personally I would do it in two steps: first read the file, then rewrite it.

@staticmethod
def set_secret_key(env_file_path, secret_key):
    with open(env_file_path, 'r') as fp:
        current_env = fp.read()

    regex = r"(SECRET_KEY=.*?)\n"
    matches = re.findall(regex, current_env, re.MULTILINE)
    updated_env = current_env.replace(matches[0], 'SECRET_KEY={}'.format(secret_key))

    with open(env_file_path, 'w')as fp:
        fp.write(updated_env)

If you want to do it in one step, use fp.seek(0) before fp.truncate() as Open file for reading and writing with truncate suggests.

@staticmethod
def set_secret_key(env_file_path, secret_key):
    fp = open(env_file_path, 'r+')

    current_env = fp.read()
    regex = r"(SECRET_KEY=.*?)\n"

    matches = re.findall(regex, current_env, re.MULTILINE)

    updated_env = current_env.replace(matches[0], 'SECRET_KEY={}'.format(secret_key))

    fp.seek(0)
    fp.truncate()
    fp.write(updated_env)

    fp.close()

Upvotes: 3

Related Questions