In [ ]:
from insupportable import Context
c = Context(version=(1,0,0))

if c.deprecated(version=(2,0,0), remove=(3,0,0)):
    pass

In [1]:
import warnings; warnings.simplefilter('default')
from insupportable import support

In [2]:
import sys
print(sys.version_info)


sys.version_info(major=3, minor=5, micro=0, releaselevel='beta', serial=2)

In [ ]:

Built-in quick support for Python 2 and 3

As a developper enable warnings, (or use python -Wd)

You support both Python 2 and Python 3 ?


In [3]:
from insupportable import support
if support('PY2'):
    print("You are on python 2")
else:
    print("You are on python 3")


You are on python 3

Drop Python 2 support:


In [4]:
from insupportable import PY2,PY3 # PY2, PY3, for convenience and avoid typos :-)

In [5]:
support.config(PY2=False)

if support(PY3):
    print("You are on python 2")
else:
    print("You are on python 3")


You are on python 2
/Users/bussonniermatthias/dev/ipykernel/ipykernel/__main__.py:3: UserWarning: PY3 is the last supported feature of this group, you can simplifiy this logic. 
  app.launch_new_instance()

(I'm writing that in IPython, so stack is wrong here)

works also if I test if(PY3) !


In [6]:
support.config(PY2=False, PY3=True) # this woudl be in config file

if support(PY3):
    print("You are on python 3")
else:
    print("You are on python 2")


You are on python 3
/Users/bussonniermatthias/dev/ipykernel/ipykernel/__main__.py:3: UserWarning: PY3 is the last supported feature of this group, you can simplifiy this logic. 
  app.launch_new_instance()

Say you use to support 3 platforms,


In [7]:
support.config(({'WindowsPhone':True,
              'Android':True,
              'iOs':False
             },))

In [8]:
if support('WindowsPhone'):
    print('Click on start menu')
else:
    print('Probably Android')


Click on start menu
/Users/bussonniermatthias/dev/insupportable/insupportable/insupportable.py:103: UserWarning: unknown feature: WindowsPhone
  warn("unknown feature: %s"%version)

And actually you decide to drop android


In [9]:
support.config(config=({'WindowsPhone':True,
              'Android':False,
              'iOs':False
             },))

In [10]:
support.config(config=({'WindowsPhone':True,
              'Android':False,
              'iOs':False
             },))
if support('WindowsPhone'):
    print('Click on start menu')
else:
    print("Probably Android - but you don't support it anymore")


Click on start menu
/Users/bussonniermatthias/dev/ipykernel/ipykernel/__main__.py:5: UserWarning: WindowsPhone is the last supported feature of this group, you can simplifiy this logic. 

In [11]:
if support('WindowsPhone'):
    print('Click on start menu')
else:
    print("Probably Android - but you don't support it anymore")


Click on start menu
/Users/bussonniermatthias/dev/ipykernel/ipykernel/__main__.py:1: UserWarning: WindowsPhone is the last supported feature of this group, you can simplifiy this logic. 
  if __name__ == '__main__':

Don't get in your way.

Nothing more anoying that having to write the configuration before actually having working code. support assume by default that you support the feature though it will warn that it does not know it. So you can just set up everything after.


In [12]:
from insupportable import support

if support('PY1'):
    # Well, we need some work around for old versions:'
    import sys
    sys.stdout.write('in python one you had to write to sys !')


in python one you had to write to sys !
/Users/bussonniermatthias/dev/insupportable/insupportable/insupportable.py:103: UserWarning: unknown feature: PY1
  warn("unknown feature: %s"%version)

It gently warn you that maybe you should tell it wether or not you stil support PY1, which let you write code and decide wether ot not to support later.

Minor python versions


In [13]:
import insupportable

In [14]:
insupportable.predicates


Out[14]:
{'PY2': False,
 'PY3': True,
 'PY30': False,
 'PY30+': True,
 'PY31': False,
 'PY31+': True,
 'PY32': False,
 'PY32+': True,
 'PY33': False,
 'PY33+': True,
 'PY34': False,
 'PY34+': True,
 'PY35': False,
 'PY35+': True,
 'PY36': False,
 'PY36+': False}

In [15]:
support('PY35+')


/Users/bussonniermatthias/dev/ipykernel/ipykernel/__main__.py:1: UserWarning: You are not supporting PY35+ anymore 
  if __name__ == '__main__':
Out[15]:
True

In [16]:
import insupportable
from insupportable import support

In [17]:
def jp():
    import sys
    return ('jupyter_notebook' in sys.modules)

support.s.add_feature('JUPYTER', jp, supported=True)

In [18]:
support('JUPYTER')


/Users/bussonniermatthias/dev/ipykernel/ipykernel/__main__.py:2: UserWarning: JUPYTER is the last supported feature of this group, you can simplifiy this logic. 
  from ipykernel import kernelapp as app
Out[18]:
True

In [19]:
class Item(object):
    
    def __init__(self, name, predicate=True, support=True):
        """An item in a discret support set.
        
        An item is consituted of 
        - a name (string)
        - a predicate (`Bool | funtion:()->Bool`) to determine if we are typically in this case.
        
        - the support status (bool)
        
        """
        self.name = name
        if callabale(predicate):
            predicate = predicate()
        self.predicate = predicate
        self.support = support

In [20]:
support.s.predicates


Out[20]:
{'PY2': False,
 'PY3': True,
 'PY30': False,
 'PY30+': True,
 'PY31': False,
 'PY31+': True,
 'PY32': False,
 'PY32+': True,
 'PY33': False,
 'PY33+': True,
 'PY34': False,
 'PY34+': True,
 'PY35': False,
 'PY35+': True,
 'PY36': False,
 'PY36+': False,
 'name': False}

technical


In [2]:
import insupportable

In [5]:
def fun(a, *args):
    print(args)

In [7]:
fun(1,2,3)


(2, 3)

In [5]:
DF


Out[5]:
<function insupportable.insupportable.DiscreatFeature>

In [ ]:


In [1]:
from insupportable import DiscreatFeature as DF, FeatureGroup#, FeatureTracker

PY2 = DF('PY2', lambda x: sys.version_info.major == 2)
PY3 = DF('PY3', lambda x: sys.version_info.major == 3)
JPY = DF('JUPYTER', lambda x: True)
IPY = DF('IPYTHON', lambda x: False)


group_py = FeatureGroup(PY2,PY3)
group_jpy = FeatureGroup(JPY,IPY)

In [116]:
vx = lambda: re.compile('^(\S+) ?(\d+)\.(\d+)(\+|-)?$')

class NumeralFeature(object):
    
    def __init__(self ,name, predicate):
        self.name = name
        self.features = []
        if callable(predicate):
            self.current_version = predicate()
        else : 
            self.current_version = predicate

In [117]:
import re

In [118]:
import sys
pyv = NumeralFeature('python', lambda :sys.version_info)

In [119]:
print(vx().search('foo2.3').groups())
print(vx().search('foo2.3+').groups())
print(vx().search('tornado 2.3-').groups())
print(vx().search('python 2.7+').groups())


('foo', '2', '3', None)
('foo', '2', '3', '+')
('tornado', '2', '3', '-')
('python', '2', '7', '+')

In [153]:
class FeatureTracker(object):

    def __init__(self, *args):
        self.args = args

        self._known_versions = [f.name for g in args for f in g.features if type(f) == DF]
        self._known_numerals = [g.name for g in args if type(g) == NumeralFeature]
        self._numeral_map = {}
        for g in args:
            if type(g) == NumeralFeature:
                self._numeral_map[g.name] = g.current_version
            else:
                continue




    def support(self, indetifier):
        pass
    
    def know(self, identifier):
        if identifier in self._known_versions:
            return True
        elif vx().match(identifier):
            feat = vx().search(identifier).groups()
            print(tuple(map(int, feat[1:3])) >= self._numeral_map[feat[0]][:2])
            return feat[0] in self._known_numerals
        
    
        
        
ft = FeatureTracker(group_jpy, group_py, pyv)

In [154]:
ft._numeral_map


Out[154]:
{'python': sys.version_info(major=3, minor=5, micro=0, releaselevel='alpha', serial=4)}

In [156]:
ft.know('python 3.5+')


True
Out[156]:
True

In [102]:
FeatureTracker


Out[102]:
__main__.FeatureTracker

So, we have a bunch of feature-sets with predicate and support:

like:

Python

- PY2   – sys.version_info.major == 2 – True
- PY3   – sys.version_info.major == 3 – True

Python3.x

- PY33 - sys.version_info.minor >=3 - True
- PY34 - sys.version_info.minor >=4 - True
- PY35 - sys.version_info.minor >=5 - True
- PY36 - sys.version_info.minor >=6 - True

PyQtGui

- PyQt   - ? - True
- PySide - ? - False


Features:

- if name not in set: warn unknown feature. 
- if last of group: warn last availlable.