Here's basic idea, based on you segregating out code into different modules. Right now, the concept is having 2 different download points. But it doesn't have to be, that's your call.
Regardless of which packaging/distribution approach you take, you'll have to separate out codelines into different code modules. Even if it's just one download.
lite/common_core.py - installed from github.lite
#things you want in common between pro and lite #i.e. what would be your "duplicate code" def common_func1(): pass
Note: I would not put stuff common to both pro and lite directly into lite/main.py, because you want to present a unified API by exposing pro in lite, but you don't want to also have pro import lite, because that would risk circular import dependencies.
lite/main.py - installed from github.lite
#things you want in common between pro and lite import lite.common_core #or import lite.common_core as common def lite_function1(): pass def lite_function2(): pass try: #you need to determine an appropriate path strategy #a pypi-installed pro package should be available on the sys.path from pro.main import * # or import pro.main as pro except ImportError: pass #client code can now call functions from the lite and pro
pro/main.py - installed from github.pro
import lite.common_core def pro_function1(): pass
You could have lite be a requirement of the pro pypi package, so that the user would still have only one download if they started that way.
Also, wrt to the answer you pointed to re git branches, another way to think of it is that you might be trying to fix/enhance say pro. So, from pro's master, you'd want the freedom to create a new branch and still be aware of lite's master (because you depend on it). That kinda bookkeeping is going to be difficult if you are juggling pro and lite on the same repo, with branches used to separate out pro/lite.