RSS
 

Python 3. Kompletne wprowadzenie do programowania – opinia

01 Sep

Pozycja Python 3. Kompletne wprowadzenie do programowania (oryg. Programming in Python 3: A Complete Introduction to the Python Language) ukazała się w Polsce nakładem wydawnictwa Helion. Niniejszy tekst stanowi próbę oceny tej książki.

“Python 3. Kompletne wprowadzenie do programowania” można podzielić na dwie główne części. Pierwsza stanowi wprowadzenie do podstawowych elementów języka, bez znajomości których ciężko byłoby stworzyć sensowny program w Pythonie. Druga natomiast to omówienie bardziej zaawansowanych technik wykorzystania biblioteki standardowej w sytuacjach uznanych przez autora za istotne.

Już we wstępie Mark Summerfield zaznacza, że książka stanowi cenne źródło wiedzy zarówno dla nowicjuszy, jak i specjalistów, w tym naukowców, związanych z programowaniem. Jak przekłada się wybór tak szerokiego spektrum odbiorców na ostateczny kształt tej pozycji? Cóż, moim zdaniem, nie do końca korzystnie. Z jednej strony autor stosuje skróty myślowe i zakłada pewną świadomość czytelnika, z drugiej z kolei opisuje przykłady w sposób dość rozwlekły. To niestety nie wpływa korzystnie na poziom pierwszej części. Zdarzało się wielokrotnie, że tekst tylko zaciemniał znaczenie omawianego kodu. Być może jest to jednak kwestia tłumaczenia, które to zasłużyło na własny akapit. Osobiście nie polecałbym również tej książki do nauki programowania jako takiego, w oderwaniu od konkretnej technologii czy języka. W pamięci utkwił mi zwłaszcza fragment rozdziału dotyczącego programowania zorientowanego obiektowo, w którym autor tworzy klasę Punkt, po czym jako jej podklasę wskazuje klasę Okrąg. Toż to jawne naruszenie koncepcji specjalizacji!

Na szczęście dalej jest już tylko lepiej. W części drugiej opisy faktycznie pomagają przyswoić materiał, a odwoływanie się do wiedzy czytelnika jest bardziej na miejscu. Na szczególną uwagę zasługuje w moim odczuciu rozdział dotyczący zaawansowanych możliwości Pythona. Naprawdę da się tu poczuć naturę tego języka. Pozytywnie odebrałem również część, w której opisano metody utrwalania danych. Odrębną kwestię stanowią ćwiczenia dołączone na końcu każdego rozdziału. Osoba chcąca poznać język w praktyce, a pozbawiona możliwości codziennej z nim pracy, może śmiało skorzystać ze wspomnianych zadań.

Niestety średnią ocenę całości zaniża tłumaczenie i korekta książki. Sporo w niej literówek i dziwnych, czasem wręcz wprowadzających w błąd sformułowań. Niepotrzebne tłumaczenia tekstów typowo technicznych, czy nawet kodu źródłowego to standard. Niech za przykład posłuży rozdział dotyczący programowania GUI. W kodzie programu definiowane są skróty klawiaturowe w postaci zwyczajowego Alt+wybrana litera opisu akcji powoduje jej uruchomienie. Nie byłoby w tym niczego złego, gdyby nie fakt, że tłumaczenia wspomnianego opisu burzy relację, czego tłumacz nie uwzględnia. Mam po prostu wrażenie, że osoba ta nie miała wiele wspólnego z procesem programowania.

Dla kogo jest zatem ta książka? Moim zdaniem dla przynajmniej średnio doświadczonego programisty, który chce poznać kolejną technologię, a któremu nie straszne jest przedzieranie się przez miejscami zawiły tok rozumowania autora. Jeśli spełniasz te warunki, na pewno wyniesiesz wiele dobrego z lektury tej pozycji.

 
No Comments

Posted in Books, Python

 

Generic relationships in Django

24 Aug

Last week I’ve completed an interesting task within our project: building internal link-shortening system based on persisted objects, not on constant URLs. The main requirement was to get as loosely-coupled design as possible. In the perfect world the “shortenable” classes should know absolutely nothing about link-shortening mechanism. How to get such a flexibility in Django? I’ve used the ContentTypes framework with generic relations and it works pretty well!

First of all, we need to prepare the model class which will keep references to every “shortanable” object and its shortening key which will be used in URLs. The key-related part is quite easy, but what about the former requirement? How it is possible to keep a relation to an object of type we don’t even know? The answer is: ContentTypes framework. It gives us an ability to get an identifier of every class within Django-based application. So, we’ve got all we need now. Just take a look into a small code snippet to see this feature in action:

class ShorteningKey(models.Model):
    """ Contains a key for a generic object used in short link resolving """
    key = models.SlugField(unique=True)
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey()

Quite neat, isn’t it? Now it is possible to get a shortening key for a given object. We’ll do that with help of the following method.

    @classmethod
    def get_shortening_key_for_instance(cls, instance):
        """ Return ShorteningKey object associated with given model object.
            May throw DoesNotExist exception """
        type = ContentType.objects.get_for_model(instance)
        return ShorteningKey.objects.get(content_type__pk=type.id, object_id=instance.id)

The last thing to do is to generate a unique key for every object. As I’ve mentioned, it was extremely important to keep “shortenable” classes as clean as possible, so hard-coding shortening key generating method within the scope of each relevant class wasn’t a good idea. Instead of this, I’ve used Signals. Now, we have to write key-generation method and associate it with post_save signal. Why do we use the post_save? Because we need persisted instance to use it within ContentTypes framework. The described function is listed below while process of attaching it to the signal will be shown later.

def generate_shortening_key(sender, **kwargs):
    """ Generates shortening key for given object """
    instance = kwargs['instance']
    new_instance_created = kwargs['created']

    if new_instance_created:
        attempt = 0
        while attempt < 100:
            try:
                shortening_key = ShorteningKey(content_object=instance, key=generate_key())
                shortening_key.save()
                break
            except DatabaseError:
                attempt += 1
        else:
            logging.warning("Cannot create link shortening for " + str(instance))

We'll also need a function which will delete unnecessary key after object deletion. It's quite simple and similar so I won't put its code here.

The whole thing is almost ready, we just need to provide a function which is responsible for retrieving shortened URL.

def get_shortened_url(instance):
    """ Returns shortened url to given instance. If there is no shortened url,
        it tries to return full url to object. If there is no one, it returns empty string.
        This function is dynamically attached to any class with link shortening enabled """
    try:
        shortening_key = ShorteningKey.get_shortening_key_for_instance(instance)
        return shortening_key.get_shortened_url()
    except ShorteningKey.DoesNotExist:
        try:
            return instance.get_absolute_url()
        except (TypeError, AttributeError):
            return ''

It will be perfect if the function would be a member of each "shortenable" class, won't it? We will attach it dynamically to each of them in the same loop which is responsible for signals attaching.

LINK_SHORTENING_ENABLED_CLASSES = (Class1,Class2,...)
for cls in LINK_SHORTENING_ENABLED_CLASSES:
    post_save.connect(generate_shortening_key, sender=cls)
    post_delete.connect(delete_shortening_key, sender=cls)
    cls.get_shortened_url = get_shortened_url

That's all! We've got fully featured link-shortening system with loosely-coupled classes. You can easily adjust this example and make it appropriate for your particular needs. For example, you can build a comment system, just like Django team did :)

 

Code coverage analysis in Django

31 Jul

Code coverage analysis could be very valuable if you want to do reliable testing. 100% coverage doesn’t give you a guarantee that everything will be fine, but still – it’s extremely useful tool. How can we use it in Django-based application?

First of all, we’ll need an awesome module called coverage.py and written by Ned Batchelder. I recommend to install it on a development machine instead of just attaching it to the project, because it can give us a huge performance boost — almost 600% during my tests.

Our next step could be a test runner concept. It is a quite good approach, because we haven’t to worry about running code coverage analysis — we can just start our tests, as we usually do. I’ve found a great code snippet with such a runner. But what if we don’t want to run analysis every time we test our application? Code coverage can be quite time-consuming while the first rule of TDD says — tests should be as fast as possible. With this thought in mind, I’ve decided to write my own Django custom command. It is based on a snippet I’ve mentioned and its aim is to run tests with code coverage analysis using a separate command. It is also able to generate pretty HTML reports (see example).

The main part of this command is a Command class.

#imports

class Command(test.Command):
    args = '[app_name ...]'
    help = 'Generates code coverage report'

    option_list = test.Command.option_list + (
            make_option('--format', '-f', dest='format', default='txt', help='Change report output format (html or txt, default: txt)'),
            make_option('--directory', '-d', dest='directory', default='.',
                        help='Change html report output directory. Default: current directory'),
        )

    def __init__(self):
        self.cov = coverage.coverage()
        self.coverage_modules = []

        self.cov.use_cache(0)

        try:
            from south.management.commands import patch_for_test_db_setup
            patch_for_test_db_setup()
        except ImportError:
            pass

    def handle(self, *test_labels, **options):
        self.__run_tests_with_coverage_analyse(test_labels, options)

        if test_labels:
            self.__add_selected_applications_to_report(test_labels)
        else:
            self.__add_all_aplications_to_report()

        if self.coverage_modules:
            self.cov.report(self.coverage_modules, show_missing=1)
            if options['format'] == 'html':
                dest_path = os.path.join(options['directory'], 'coverage_report')
                self.__generate_html_report(dest_path)

        self.cov.erase()

    def __run_tests_with_coverage_analyse(self, test_labels, options):
        self.cov.start()
        super(Command, self).handle(*test_labels, **options)
        self.cov.stop()

    def __add_selected_applications_to_report(self, test_labels):
        for label in test_labels:
            # Don't report coverage if you're only running a single
            # test case.
            if '.' not in label:
                app = get_app(label)
                self.coverage_modules.extend(self.__get_coverage_modules(app))

    def __add_all_aplications_to_report(self):
        for app in get_apps():
            self.coverage_modules.extend(self.__get_coverage_modules(app))

    def __generate_html_report(self, dest_dir):
        print "Generating HTML report in %s..." % dest_dir
        self.__delete_directory_content(dest_dir)
        self.cov.html_report(self.coverage_modules, directory=dest_dir)

    def __get_coverage_modules(self, app_module):
        """
        Returns a list of modules to report coverage info for, given an
        application module.
        """
        app_path = app_module.__name__.split('.')[:-1]
        coverage_module = __import__('.'.join(app_path), {}, {}, app_path[-1])

        #ignore external modules/applications
        module_path = coverage_module.__path__[0]
        if 'webapp/apps' not in module_path:
            return []

        return [attr for name, attr in
            getmembers(coverage_module) if ismodule(attr) and name != 'tests']

#some other stuffs
    As we can see in lines 7-11, it has two additional options:

  • -f or --format which can take a html value to generate an HTML report
  • -d or --directory which can take a path to destination directory where an HTML report will be saved to

Either we decide to generate an HTML report or not, we’ll always get a text report in the console. Moreover, the default localization of this report is current directory, so we haven’t to declare a -d parameter at all.

Line 21 is very important too. You’ve to call this function, if you use South migrations in your application. Otherwise your tests will fail.

Obviously, this command works just as classic test command. You can call all tests with ./manage.py code_coverage. You can also run tests for selected modules, ex. ./manage.py code_coverage app1 app2.

I hope it’ll be helpful. I’m also open to any ideas.

 

How to add a text message to messages conversation in Android SDK

25 Jul

Today I’ve published new version of my Andriod application – AutoRespnder. The main feature in this release was quite simple: show auto-sent messages within standard messages conversation, just as if was send by hand. How to do this in Android SDK?

Because it is a background operation not visible to user, I’ve decided to build a Service to accomplish this task.

//imports

public class SentSmsLogger extends Service {

	private static final String TELEPHON_NUMBER_FIELD_NAME = "address";
	private static final String MESSAGE_BODY_FIELD_NAME = "body";
	private static final Uri SENT_MSGS_CONTET_PROVIDER = Uri.parse("content://sms/sent");

	@Override
	public void onStart(Intent intent, int startId) {
		addMessageToSentIfPossible(intent);
		stopSelf();
	}

	private void addMessageToSentIfPossible(Intent intent) {
		if (intent != null) {
			String telNumber = intent.getStringExtra("telNumber");
			String messageBody = intent.getStringExtra("messageBody");
			if (telNumber != null && messageBody != null) {
				addMessageToSent(telNumber, messageBody);
			}
		}
	}

	private void addMessageToSent(String telNumber, String messageBody) {
		ContentValues sentSms = new ContentValues();
		sentSms.put(TELEPHON_NUMBER_FIELD_NAME, telNumber);
		sentSms.put(MESSAGE_BODY_FIELD_NAME, messageBody);

		ContentResolver contentResolver = getContentResolver();
		contentResolver.insert(SENT_MSGS_CONTET_PROVIDER, sentSms);
	}

	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}

}

SentSmsLogger expects Intent with receiver number and message body. Then it passes that information to proper ContetProvider.

And this is the clue – it isn’t well documented how to manage ContentProvider associated with messaging module. Google to the rescue ;) I’ve found an information that relevant ContentProvider has URI content://sms/sent. Next step was to find out what are the names of fields that contains data about message body and its receiver. With the help of debugger, I’ve found them – it’s body and address. I’ve put all of this in private constants in the top of class.

That’s all! Now we’ve to use this data in a standard manner. Useful information about that can be found in official documentation.

Important note: due to compatibility issues, I’ve used Android SDK v. 1.5 here.

 

Spring – kontener wstrzykiwania zależności

24 Jul

Czym jest Spring?

Spring Framework jest to platforma, której głównym celem jest uproszczenie procesu tworzenia oprogramowania klasy enterprise w technologii Java/J2EE. Rdzeniem Springa jest kontener wstrzykiwania zależności, który zarządza komponentami i ich zależnościami. Umożliwia on automatyczne wykrywanie tych zależności bez większego udziału programisty. Nie ma także problemu z własnoręczną konfiguracją – jeśli taki sposób pracy bardziej nam odpowiada. Cel jest jednak jeden – zmniejszenie stopnia związania klas. Artykuł ten ma za zadanie zaprezentować Springa właśnie w tym kontekście. Ale o tym za chwilę – najpierw kilka słów o architekturze frameworka.

Architektura Spring Framework

Spring jest rozwiązaniem modułowym. Bez problemu możemy wykorzystać jedynie te części, których potrzebujemy. W skrócie omówię niektóre z nich.

Architektura Spring Framework

Core Container

Core i Beans – podstawowe moduły, zawierają funkcjonalność Inversion of Control i Dependency Injection, będące tematem przewodnim niniejszego artykułu. To dzięki nim możliwe jest oddzielenie konfiguracji i specyfikacji zależności od logiki biznesowej.

Context – zapewnia dostęp do obiektów na poziomie frameworka w sposób analogiczny do JNDI. Dodaje wsparcie dla internacjonalizacji i propagowania zdarzeń, a także EJB i JMX.

DAO

DAO zapewnia wsparcie dla metod utrwalnia obiektów, w szczególności JDBC, ORM, OXM (mapowanie XML), JMS (tworzenie i przetwarzanie wiadomości). Dostarcza gotową do wykorzystania pulę połączeń, a także możliwość deklaratywnego definiowania transakcji. Pozwala na łatwe mapowanie ResultSetów na listę obiektów klas domenowych.

Web

Web zawiera własny framework webowy – Spring Web MVC. Pozwala także wykorzystywać inne technologie, np. Struts, JSF, Velocity. Wspomaga proces ładowania plików na serwer.

AOP

AOP wspiera programowanie zorientowane aspektowo zarówno w wydaniu prostszym (Spring AOP), jak i bardziej rozbudowanym (AspectJ).

Test

Test zawiera mechanizmy służące do testowania aplikacji (JUnit lub TestNG). W szczególności dostarcza mocków.

Read the rest of this entry »

 

Null Value on Save Issue in Grails

22 Jul

If you’ve used Grails, you’re probably familiar with a domain class and its “constraints” block. There you can define conditions which have to be met by class’s fields. For example, you can enforce that a field have to be not-empty using “blank: false” condition. It’d be intuitive not to define conditions for the field you don’t care of. Unfortunately, there is a small trap here. Let’s use an example to explain it.

Let’s define an Invoice class with a few fields: number, draw date and payment date. The number and draw data are obligatory while the payment date isn’t, because you’re able to pay for an invoice by cash.

class Invoice {
	String number;
	Date drawDate;
	Date paymentDate;
	static constraints = {
		number(blank: false);
		drawDate(blank: false);
	}
}

It looks good, doesn’t it? You can generate controller and views for that class and test it in a browser. Try to leave a payment date field empty and save an invoice. Success – it works! OK, so let’s create a BootStrap entry for our new class. Again, try to omit its optional field – paymentDate.

def invoice = new Invoice(number: “1/2010”, drawDate: new Date()).save();

What value does invoice variable have? Null! What’s wrong? Why does it work in a browser and not directly in a code?

The answer is quite straight, but I haven’t found it in a documentation. The default, implicit value of a field’s constraint is “nullable: false”. When you fills in a form in your browser, you really sends a blank value – empty string. This string isn’t null so it meets “nullable: false” criteria. On the other hand, if you creates a new object in your code and you omits a field, you pass a null value and hence the validator doesn’t allow to create an object! Unfortunately, Grails doesn’t provide any descriptive message on what’s really going under the hood.

What can you do? You can set an explicit constraint for such a field: “nullable: true”. The complete class would be:

class Invoice {
	String number;
	Date drawDate;
	Date paymentDate;
	static constraints = {
		number(blank: false);
		drawDate(blank: false);
		paymentDate(nullable: true);
	}
}

Personally, I suggest to set “nullable: true” constraint for every field which is optional and “blank: false” for every obligatory field.

This article was previously posted at Groovy Zone.

 

Initial value of primary key in Grails

22 Jul

I’ve recently came across a small issue in my Grails application. I had to set an initial value of auto-generated identifiers of my objects. Moreover, I had to use two different values in two classes. For example, identifiers in one table in database should start from 50, while in another table – from 1000. How to get this in Grails domain classes?

You have to use SequenceStyleGenerator with its parameter – initial_value. You can do this with generator phrase in mapping clousure:

class FirstClass {
  static mapping = {
    id(generator: 'org.hibernate.id.enhanced.SequenceStyleGenerator',
       params: [initial_value: 50])
  }
  ...
}

class SecondClass {
  static mapping = {
    id(generator: 'org.hibernate.id.enhanced.SequenceStyleGenerator',
       params: [initial_value: 1000])
  }
  ...
}

Unfortunately, in this case you’ll finish with the same sequence generator in both classes. That means that you’ll get one sequence shared between two tables. How to avoid this? Just specify sequence name using next parameter – sequence_name:

class FirstClass {
  static mapping = {
    id(generator: 'org.hibernate.id.enhanced.SequenceStyleGenerator',
       params: [sequence_name: 'first_seq', initial_value: 50])
  }
  ...
}

class SecondClass {
  static mapping = {
    id(generator: 'org.hibernate.id.enhanced.SequenceStyleGenerator',
       params: [sequence_name: 'second_seq', initial_value: 1000])
  }
  ...
}

What do you think about my solution? Do you know another one?


This article was previously posted at Groovy Zone.