Git – rename a file

Here’s how I just renamed a file under a git repository since I didn’t want to lose tracking changes by just deleting the old file and adding the new one to the repository. Although I use SmartGit but I had to do the renaming part on the terminal.

1. Rename the file using git command

$ git mv old_filename new_filename

2. Use git status to check the old and new file names.

$ git status
# On branch your-branch
# Changes to be committed:
#   (use "git reset HEAD ..." to unstage)
#
#     renamed: old_filename -> new_filename
#

3. Commit the file using SmartGit or from terminal using

$ git commit -m "Rename file"

4. Push changes to the remote repository from SmartGit or from terminal using

$ git push
Advertisements

Installing / Re-Installing Apache, PHP, libapache2-mod-php

The following is done on an Ubuntu machine but hoping it should cover other Debian instances.

I accidentally deleted php7.0.conf and php7.0.load from the mods-available folder. These files come with libapache2-mod-php. I uninstalled the module and installed it again – but the files didn’t appear. A lot of blogs suggested to remove Apache, PHP and libapache2-mod-php altogether and installing it again and it didn’t work. I used remove, purge and everything suggested but didn’t help. Eventually, I had to search for the installed module by:

dpkg --get-selections | grep libapache2-mod-php

I installed the module above as is but the result showed me libapache2-mod-php7.0. So I went ahead and removed and purged the module listed after which I installed the module again (without the 7.0 suffix) and I was able to recover the files again.

apt-get remove --purge libapache2-mod-php7.0
apt-get install libapache2-mod-php

Since I am covering this topic, let’s talk about installing Apache on Debian and the supported PHP packages along with SSL support.

apt-get install apache2
apt-get install php
apt-get install php-curl
apt-get install libapache2-mod-php

Enable SSL on the site:

cd /etc/apache2/sites-enabled
ln -fs ../sites-available/default-ssl.conf 

Finally, add the necessary modules to support PHP/SSL on Apache

cd /etc/apache2/mods-enabled
ln -fs ../mods-available/ssl.conf
ln -fs ../mods-available/ssl.load 
ln -fs ../mods-available/socache_shmcb.load
ln -fs ../mods-available/php7.0.conf
ln -fs ../mods-available/php7.0.load

Do not forget to restart apache with

service apache2 restart

Python – Iterate over a list and check if it’s not Empty

I have a list that I wanted to iterate over. When I used a list comprehension, it would fail if the list was None. But it would if the list was empty [].

The old and easy way of doing this was:

if tags:
	for t in tags:
		# Do stuff with t

The pythonic way of merging the if statement within the list comprehension is:

for t in [t for t in (tags or [])]:
	# Do stuff with t

If you had a dictionary, you could use a ternary condition within list comprehension:

([k for k, v in tags] if tags is not None else [])

OR, You can embed the ternary condition in the comprehension as well:

[k for k, v in (tags if tags is not None else [])]

The original stack overflow post.

Python Class used like an Enum

Although Enums are available in Python, I just like the idea or am used to using Classes instead which allows me to have more functionality in future if I need to attach additional methods to the class. Here’s how I have typically created a Class to store AWS Regions and have a method all() that would return all the region values – basically hard-coded.

class AwsRegion():
	'''
	Class to define AWS Regions
	'''
	OHIO = 'us-east-2'
	NORTH_VIRGINIA = 'us-east-1'
	NORTH_CALIFORNIA = 'us-west-1'
	OREGON = 'us-west-2'
	MUMBAI = 'ap-south-1'
	SEOUL = 'ap-northeast-2'
	SINGAPORE = 'ap-southeast-1'
	SYDNEY = 'ap-southeast-2'
	TOKYO = 'ap-northeast-1'
	FRANKFURT = 'eu-central-1'
	IRELAND = 'eu-west-1'
	LONDON = 'eu-west-2'
	SAO_PAULO = 'sa-east-1'

	@classmethod
	def all(cls, ):
		return [
			AwsRegion.OHIO,
			AwsRegion.NORTH_VIRGINIA,
			AwsRegion.NORTH_CALIFORNIA, 
			AwsRegion.OREGON,
			AwsRegion.MUMBAI,
			AwsRegion.SEOUL,
			AwsRegion.SINGAPORE,
			AwsRegion.SYDNEY,
			AwsRegion.TOKYO,
			AwsRegion.FRANKFURT,
			AwsRegion.IRELAND,
			AwsRegion.LONDON,
			AwsRegion.SAO_PAULO
			]

But I wanted to make the method all() more dynamic so every time I add new regions to the class, I don’t have to add the region to the all method return list. I found a better way to implement the all() method.

@classmethod
def all(cls, ):
	return [value for name, value in vars(cls).items()
				if not name.startswith('__')
					and not callable(getattr(cls,name))]

The original stack overflow post.

Django Signals

Django includes a “signal dispatcher” which helps allow decoupled applications get notified when actions occur elsewhere in the framework. In a nutshell, signals allow certain senders to notify a set of receivers that some action has taken place. They’re especially useful when many pieces of code may be interested in the same events.

Django provides a set of built-in signals that let user code get notified by Django itself of certain actions. They may be useful when you’d like to take certain actions pre/post saving/deleting of objects. These include some useful notifications:

  • django.db.models.signals.pre_save & django.db.models.signals.post_save
  • django.db.models.signals.pre_delete & django.db.models.signals.post_delete

See the built-in signal documentation for a complete list, and a complete explanation of each signal.

Listening to signals
To receive a signal, you need to register a receiver function that gets called when the signal is sent by using the Signal.connect() method:

Signal.connect(receiver, sender=None, weak=True, dispatch_uid=None)

Receiver functions
First, we need to define a receiver function. A receiver can be any Python function or method:

def my_callback(sender, **kwargs):
    print("Request finished!")

Example of logging changes in Django application

Log changes on pre_save of object

def log_change_to_admin(sender, instance, **kwargs):
    '''
    Custom audit trail for any model.  This adds an entry into the django admin logs.  We'll get two entries per edit but at least we'll have the changes.
    Handles cases where the user adds or edits a model
    '''
    try:
        #if you want to override the log object do it as a _log_obj method on the instance, returning an object
        log_obj = instance._log_obj()
    except:
        log_obj = instance
    try:
        #if you want to override the excluded fields do it as a _log_excluded_fields method on the instance, returning a list
        excluded_fields = instance._log_excluded_fields()
    except:
        excluded_fields = []

    try:

        log_message = None

        #the "raw" check is to make sure we are not loading fixtures
        if not kwargs["raw"]:

            #if there is an id then we are in an edit situation
            if instance.id:
                #get the old object from the database
                old = sender.objects.get(pk=instance.id)

                #figure out what changed
                changed = []
                if old._meta and old._meta.fields:
                    for f in [field for field in old._meta.fields if field.name not in excluded_fields]:
                        if getattr(instance, f.name) != getattr(old, f.name):
                            old_value = "'%s'" % getattr(old, f.name)
                            new_value = "'%s'" % getattr(instance, f.name)
                            changed.append((f.name, old_value, new_value))

                #only log stuff if it has changed.
                if changed:
                    log_message = "Changes to %s: " % instance.__unicode__()
                    log_message += ', '.join(["%s from %s to %s" % (x[0], x[1], x[2]) for x in changed])
                    flag = CHANGE

            #since there was no id then we are in an add situation
            else:
                log_message = "Added %s: %s" % (sender.__name__, instance.__dict__)
                flag = ADDITION

        if log_message:
            u = 1 #default to root user if the request object is not attached.

            #add to the django log
            LogEntry.objects.log_action(
                user_id = u,
                content_type_id = ContentType.objects.get_for_model(log_obj).id,  #content_type_id for the account object
                object_id = log_obj.id,
                object_repr = log_obj.__unicode__(),
                change_message = log_message.rstrip(),
                action_flag = flag,
                )
    except:
        print "Failed to log action."

#connect log_change_to_admin to the pre_save signal for Installations and associated children
models.signals.pre_save.connect(log_change_to_admin, sender=Installation)

Log changes on pre_delete of object

def log_delete_to_admin(sender, instance, **kwargs):
    '''
    Custom audit trail for models.  This adds an entry into the django admin logs.  We'll get two entries per edit but at least we'll have the changes.
    Handles cases where the user deletes a model
    '''
    try:
        #if you want to override the log object do it as a _log_obj method on the instance, returning an object
        log_obj = instance._log_obj()
    except:
        log_obj = instance

    try:

        log_message = "Deleting %s: %s" % (instance.__unicode__(), instance.__dict__)

        u = 1 #default to root user if the request object is not attached.

        #add to the django log
        LogEntry.objects.log_action(
            user_id = u,
            content_type_id = ContentType.objects.get_for_model(log_obj).id,  #content_type_id for the account object
            object_id = log_obj.id,
            object_repr = log_obj.__unicode__(),
            change_message = log_message.rstrip(),
            action_flag = DELETION,
            )
    except:
        print "Failed to log action."

#connect log_delete_to_admin to the pre_delete signal for Installations and associated children
models.signals.pre_delete.connect(log_delete_to_admin, sender=Installation)

You can define your own custom rules and attach them to signals. e.g. I wanted to conditionally do some synchronization with SFDC after the object was saved. I created a post_save signal and hooked it up with a receiver that did the job.

# receiver to work on the SFDC changes for incoming request
def syncAccountToSfdc(sender, instance, **kwargs):
    if instance.isCustomer() and instance.account.salesforce_type != instance.account.getComputedSfdcAccountType() \
    and instance.account.salesforce_type in [SfdcAccountType.CUSTOMER, SfdcAccountType.CUSTOMER_IN_DANGER, SfdcAccountType.FORMER_CUSTOMER]:
        instance.account.update_salesforce()

# post_save signal to sync to SFDC if required
models.signals.post_save.connect(syncAccountToSfdc, sender=Installation)

Updating Nulls in SFDC using salesforce-python-toolkit

I had been looking for a long time to update Null into a SFDC field. I wanted to set the date value to current date or reset it to blank based on a condition. I was able to set a date without issues, but clearing the date wouldn’t work. I tried to use ”, ‘null’ and None while trying to blank out the value but nothing worked. I was sure it was a straightforward solution but just didn’t know what it was. I got in touch with the author of the toolkit and he responded back in no time with the solution. I’m sharing the working solution here:

data = {}
if condition==True:
    data['Termination_Date__c'] = '2017-05-12'
else:
    data['fieldsToNull'] = ['Termination_Date__c']