Skip to content

Commit

Permalink
Versioning Proof of Concept
Browse files Browse the repository at this point in the history
This is an example of a versioned system of development that makes previous versions still available for usage.
This style would be most useful for things such as an API where different versions of the API may be desirable
 (e.g. exposing the legacy SickBeard API and the future Medusa API)
 It has the benefit that older methods can be deprecated with minimal, or at least delayed, impact.
 It can also be beneficial for providing multiple "program flows" for different use-cases.

 Some "gotchas" regarding mutables are also shown, however it should be noted that the issues with mutables
 are not specific to versioned imports, but might be less likely to be noticed in some situations.

 Run test.py to test
  • Loading branch information
labrys committed May 6, 2016
1 parent 1b76dbc commit f825938
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 0 deletions.
Empty file added medusa/__init__.py
Empty file.
52 changes: 52 additions & 0 deletions medusa/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@

from __future__ import absolute_import, print_function
from medusa import ver

print('\nSimple display of versions')
print(ver.version) # current version can be imported into the package namespace to make it directly available
print(ver.test.version) # or it can be merged as a package without an explicit version name for the "current" version
print(ver.test_v0.version) # or you can have each available version imported separately
print(ver.test_v1.version)
print(ver.test_v1_0.version)
print(ver.test_v1.version) # this shows that the modification in v1_0 did not change the v1 version

print('\nBe careful with mutables!!')
print(ver.failed_list)
print(ver.test.failed_list) # not a mutable, so no modification
print(ver.test_v0.failed_list) # all the changes to the mutable, though...
print(ver.test_v1.failed_list) # have been mirrored to all the modules
print(ver.test_v1_0.failed_list)
print(ver.test_v1.failed_list)

print('\nSafer mutables using typecasting')
# typecasting the mutable is a safer alternative as it makes it a copy of the original
print(ver.better_list)
print(ver.test.better_list)
print(ver.test_v0.better_list)
print(ver.test_v1.better_list)
print(ver.test_v1_0.better_list)
print(ver.test_v1.better_list)

print('\nStill be careful with nested mutables!!!') # the nested mutable is not a copy! it is just a shared reference across all the mutables
# nest a mutable
ver.better_list.append(['g', 'h', 'i'])
# both change
print(ver.better_list)
print(ver.test_v1_0.better_list)

print('\nThinking that the typecast will fix all problems...')
be_careful = list(ver.better_list)
be_careful.append('z')

print(be_careful)
print(ver.better_list)
print(ver.test_v1_0.better_list)

print('\n...may lead to some surprising problems!')
ver.better_list[-1].append('WTF?!?')
print(be_careful)
print(ver.better_list)
print(ver.test_v1_0.better_list)

print('\nKeep in mind these problems with mutables are not exclusive to these types of imports,'
'\nbut these imports can mask the source problem, making it difficult to notice these issues.')
9 changes: 9 additions & 0 deletions medusa/ver/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

from __future__ import absolute_import, print_function

from ver.v0 import test as test
from ver.v0 import test as test_v0
from ver.v1 import test as test_v1
from ver.v1.v1_0 import test as test_v1_0

from ver.v1.v1_0.test import version, failed_list, better_list
Empty file added medusa/ver/v0/__init__.py
Empty file.
5 changes: 5 additions & 0 deletions medusa/ver/v0/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

from __future__ import absolute_import, print_function
version = 'v0'
failed_list = 1 # not a list in v0
better_list = 'a' # not a list in v0
Empty file added medusa/ver/v1/__init__.py
Empty file.
5 changes: 5 additions & 0 deletions medusa/ver/v1/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

from __future__ import absolute_import, print_function
version = 'v1'
failed_list = [1, 2, 3] # now a list in v1
better_list = ['a', 'b', 'c'] # now a list in v1
Empty file added medusa/ver/v1/v1_0/__init__.py
Empty file.
13 changes: 13 additions & 0 deletions medusa/ver/v1/v1_0/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

from __future__ import absolute_import, print_function

from medusa.ver.v1.test import version, failed_list, better_list

version += '.0'

# here's where problems start... lists are mutable so mutable imported from other package also gets changed
failed_list.extend([4, 5, 6])

# typecasting it with list() is a better approach as it makes a copy
better_list = list(better_list)
better_list.extend(['d', 'e', 'f'])

0 comments on commit f825938

Please sign in to comment.