HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Package Manager in Python

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
managerpythonpackage

Problem

I've written a package manager for OS X in order to improve my Python skills. This is the second programming project I've ever worked on, so I do not expect it to be great, or anything, but I would like to get some input on the code and overall design.

I store the package info inside a SQLite database, which I've written a class to work with. The main file contains another class which is supposed to be a library, so a working program would interact with it.

This is the first time I've used a VCS, so I chose git, and I uploaded the repo to github.

And here is the code

lazy.py

```
#!/usr/bin/env python3
"""
This is the main class for Lazy. It provides all the basic operations the
package manager should support in the forms of class methods. If you want to
actually use Lazy, you need to write an interface for it. Lazy was written with
Python 3 in mind, but it should work with Python 2 with minimal modification.
"""
import os
import os.path
import tarfile
import hashlib
import urllib.request
import subprocess
import shutil
import lazy_db

class Lazy(lazy_db.LazyDB):

prefix = os.path.join("/usr", "local", "lazy")
bindir = os.path.join(prefix, "bin")
log_path = os.path.join(prefix, "logs")
patch_path = 'patch'
autoconf_ext = '.autoconf'
patch_ext = '.patch'
automake_ext = '.make'

def install(self, pkg_id):
"""
This method takes a package id and installs the associated package. It
does so by getting all the information from the database and calling
different methods to perform the installation steps.
"""
self.resolve_dependencies(pkg_id)

(self.pkg_id, self.name, self.download_url, self.md5,
self.srcdir, self.objdir, self.args, self.installed_version,
self.latest_version) = self.get_all_package_info(pkg_id)

self.filename = self.download_package()
self.extract_package()
self.autoconf()
self.automake()
self.symlink()

Solution

def install(self, pkg_id):
    """
    This method takes a package id and installs the associated package. It
    does so by getting all the information from the database and calling
    different methods to perform the installation steps.
    """
    self.resolve_dependencies(pkg_id)

    (self.pkg_id, self.name, self.download_url, self.md5,
    self.srcdir, self.objdir, self.args, self.installed_version,
    self.latest_version) = self.get_all_package_info(pkg_id)


That's a lot of data to be fetching. What if you want to add or remove or change the order of some of that? Instead, put all of that information into a Package class and return that.

Don't store temporary state on self. If you need to pass temporary information use parameters.

get_all_package_info is from LazyDB. But Lazy uses LazyDB it is not a specialization of LazyDB. So you shouldn't inherit from LazyDB, instead you should store a refence to LazyDB as self.db.

self.filename = self.download_package()
    self.extract_package()
    self.autoconf()
    self.automake()
    self.symlink()
    self.cleanup()


All of this relates specifically to the package, it should all really be done by calling package.install() where package is the package object you should return.

Overall, this function should look like

def install(self, pkg_id):
    package = self.db.load(pkg_id)
    self.resolve_dependencies(package)
    package.install()


You've got functions to manipulate pretty much every possible field you might want to change in the database. Instead, I'd suggest having a few functions, that work with Package objects.

The thing with package managers is that you typically want to update the package details without changing the information about what the user has installed. But you've got that data in the same table. What you probably want to do is actually have two databases. One database has the package information, and you update it by downloading a new copy to replace the old one. The other package has the installation information.

Code Snippets

def install(self, pkg_id):
    """
    This method takes a package id and installs the associated package. It
    does so by getting all the information from the database and calling
    different methods to perform the installation steps.
    """
    self.resolve_dependencies(pkg_id)

    (self.pkg_id, self.name, self.download_url, self.md5,
    self.srcdir, self.objdir, self.args, self.installed_version,
    self.latest_version) = self.get_all_package_info(pkg_id)
self.filename = self.download_package()
    self.extract_package()
    self.autoconf()
    self.automake()
    self.symlink()
    self.cleanup()
def install(self, pkg_id):
    package = self.db.load(pkg_id)
    self.resolve_dependencies(package)
    package.install()

Context

StackExchange Code Review Q#10816, answer score: 4

Revisions (0)

No revisions yet.