Skip to Content.
Sympa Menu

cc-licenses - Re: relicensing rules encoded

cc-licenses AT lists.ibiblio.org

Subject: Development of Creative Commons licenses

List archive

Chronological Thread  
  • From: Mike Linksvayer <ml AT creativecommons.org>
  • To: Discussion on the Creative Commons license drafts <cc-licenses AT lists.ibiblio.org>
  • Subject: Re: relicensing rules encoded
  • Date: Mon, 21 Mar 2005 16:11:00 -0800

I've attached a slightly updated version that mentions cross-jurisdiction compatibility as raised by Bjorn Wijers and also says that apart from ShareAlike you can do whatever you want, it just might not be clear, and that IANAL, this is not legal advice, etc.

--
Mike Linksvayer
http://creativecommons.org/about/people#21
# relicense.py
#
# encodes rules for relicensing Creative Commons licensed works
#
# relicense() function contains the logic
#
# combine() accepts multiple licenses, calls relicense() for
# each and returns intersection of allowable licenses
#
# see tests at end for expected values
#
# read comments in relicense() for explanation of rules
#
# Further Notes:
#
# - This program does not specify jurisdiction. Relicensing should be
# compatible across jurisdictions and are explicitly so for ShareAlike.
#
# - Apart from ShareAlike the licenses don't explicitly say how you may
# relicense works. Perhaps you could incorporate a NC work into your
# non-NC work and specify that portions are not available for commercial
# user, though such may be confusing for users. The output of this
# program attempts to be conservative.
#
# - Nothing in this program nor its output should be considered legal
# advice. The program's author is not a lawyer.

import copy

DEBUG = 0
LICENSES =
['by','by-nc','by-nc-nd','by-nc-sa','by-nd','by-sa','nc-sampling+','publicdomain','sampling','sampling+']

def debug(msg):
if (DEBUG):
print msg

# keep only licenses matching 'keep' parameter
def keep(licenses, keep):
for license in copy.copy(licenses):
if (license.find(keep) == -1):
licenses.remove(license)
debug('keep: '+keep+' REMOVED: '+license)
else:
debug('keep: '+keep+' KEPT: '+license)

# remove licenses matching 'remove' parameter
def remove(licenses, remove):
for license in copy.copy(licenses):
if (license.find(remove) != -1):
licenses.remove(license)
debug('remove: '+remove+' REMOVED: '+license)
else:
debug('remove: '+remove+' KEPT: '+license)

# allowed relicensing options for a single license
def relicense(license):
relicenses = copy.copy(LICENSES)
# PD allows anything
if (license.find('publicdomain') != -1):
return relicenses
# sampling requires attribution although 'by' isn't in the URI
if (license.find('by') != -1 or license.find('sampling') != -1):
remove(relicenses,'publicdomain')
# noncommercial must be propagated
if (license.find('nc') != -1):
keep(relicenses,'nc')
# noderivs must be propagated. note that this is only good for
# redistribution of verbatim copies, does not allow derivative works
if (license.find('nd') != -1):
keep(relicenses,'nd')
# sharealike requires exact license match
if (license.find('sa') != -1 and license.find('sampling') == -1):
keep(relicenses,license)
# sampling requires another sampling license to propagate
# no advertising and transformation requirement
# unadorned sampling requires unadorned sampling to propagate
# no verbatim distribution
if (license.find('sampling') != -1):
keep(relicenses, 'sampling')
if (license.find('sampling+') == -1):
remove(relicenses,'sampling+')
return relicenses

# intersection of allowed relicensing options for each license
def combine(licenses):
relicenseset = None
for license in licenses:
thisrelicenseset = set(relicense(license))
if (relicenseset == None):
relicenseset = thisrelicenseset
else:
relicenseset = relicenseset.intersection(thisrelicenseset)
if (DEBUG):
debug('Combining: '+license+' this: '+str(thisrelicenseset)+'
sofar: '+str(relicenseset))
return relicenseset

def test(license, expectedrelicenses):
if (isinstance(expectedrelicenses,set)):
relicenses = combine(license)
else:
relicenses = relicense(license)
if (relicenses == expectedrelicenses):
print 'PASS:', license, 'expected&got:', relicenses
else:
print 'FAIL:', license, 'expected:', expectedrelicenses, 'got:',
relicenses

# test each license against expected values
test('by',['by','by-nc','by-nc-nd','by-nc-sa','by-nd','by-sa','nc-sampling+','sampling','sampling+'])
test('by-nc',['by-nc','by-nc-nd','by-nc-sa','nc-sampling+'])
test('by-nc-nd',['by-nc-nd'])
test('by-nc-sa',['by-nc-sa'])
test('by-nd',['by-nc-nd','by-nd'])
test('by-sa',['by-sa'])
test('nc-sampling+',['nc-sampling+'])
test('publicdomain',LICENSES)
test('sampling',['sampling'])
test('sampling+',['nc-sampling+','sampling','sampling+'])

# test just a few multi-license combinations
test(['by-nc-sa','nc-sampling+'],set([]))
test(['by-sa','by-nc-sa'],set([]))
test(['by','publicdomain','sampling+'],set(['nc-sampling+','sampling','sampling+']))
test(['by-nc','sampling+'],set(['nc-sampling+']))




Archive powered by MHonArc 2.6.24.

Top of Page