Skip to content
This repository has been archived by the owner on Jan 30, 2019. It is now read-only.

Add versioning to conda envs #271

Open
wants to merge 9 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion conda_env/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,12 @@ def unique(seq, key=None):

class Environment(object):
def __init__(self, name=None, filename=None, channels=None,
dependencies=None, prefix=None):
dependencies=None, prefix=None, version=None, summary=None):
self.name = name
self.filename = filename
self.prefix = prefix
self.version = version
self.summary = summary
self.dependencies = Dependencies(dependencies)

if channels is None:
Expand All @@ -151,6 +153,10 @@ def to_dict(self):
d['dependencies'] = self.dependencies.raw
if self.prefix:
d['prefix'] = self.prefix
if self.version:
d['version'] = self.version
if self.summary:
d['summary'] = self.version
return d

def to_yaml(self, stream=None):
Expand Down
62 changes: 46 additions & 16 deletions conda_env/specs/binstar.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@
from binstar_client import errors
from binstar_client.utils import get_binstar
except ImportError:
get_binstar = None
get_binstar= None
try:
from binstar_client.utils import get_server_api
except ImportError:
get_server_api = None
from binstar_client.utils.spec import parse_specs

ENVIRONMENT_TYPE = 'env'
# TODO: isolate binstar related code into conda_env.utils.binstar


class BinstarSpec(object):
"""
spec = BinstarSpec('darth/deathstar')
Expand All @@ -26,13 +30,14 @@ class BinstarSpec(object):
_packagename = None
_package = None
_file_data = None
_specs = None
msg = None

def __init__(self, name=None, **kwargs):
self.name = name
self.quiet = False
if get_binstar is not None:
self.binstar = get_binstar()
if get_server_api is not None:
self.binstar = get_server_api()
else:
self.binstar = None

Expand Down Expand Up @@ -69,6 +74,12 @@ def valid_package(self):
"""
return len(self.file_data) > 0

@property
def specs(self):
if self._specs is None:
self._specs = parse_specs(self.name)
return self._specs

@property
def file_data(self):
if self._file_data is None:
Expand All @@ -81,15 +92,23 @@ def environment(self):
:raises: EnvironmentFileNotDownloaded
"""
if self._environment is None:

versions = [{
'normalized': normalized_version(d['version']),
'original': d['version']} for d in self.file_data]
latest_version = max(versions, key=lambda x: x['normalized'])['original']
file_data = [data for data in self.package['files'] if data['version'] == latest_version]
req = self.binstar.download(self.username, self.packagename, latest_version, file_data[0]['basename'])

if self.version:
file_data = [data for data in self.package['files'] if data['version'] == self.version]
req = self.binstar.download(self.username, self.packagename, self.version, file_data[0]['basename'])
else:
latest_version = max(versions, key=lambda x: x['normalized'])['original']
file_data = [data for data in self.package['files'] if data['version'] == latest_version]
req = self.binstar.download(self.username, self.packagename, latest_version, file_data[0]['basename'])

if req is None:
raise EnvironmentFileNotDownloaded(self.username, self.packagename)
self._environment = req.text

return env.from_yaml(self._environment)

@property
Expand All @@ -105,16 +124,27 @@ def package(self):

@property
def username(self):
if self._username is None:
self._username = self.parse()[0]
return self._username
if self.specs._user is None:
self.specs_error()
else:
return self.specs._user

@property
def version(self):
if self.specs._version is None:
return None
else:
return self.specs._version

@property
def packagename(self):
if self._packagename is None:
self._packagename = self.parse()[1]
return self._packagename
if self.specs._package is None:
self.specs_error()
else:
return self.specs._package

def parse(self):
"""Parse environment definition handle"""
return self.name.split('/', 1)
def specs_error(self):
self.msg = "{} was not able to parsed.\n"\
"Package name should be either user/package: darth/deathstar:\n"\
"Or user/package/version darth/deathstar/1.0".format(self.name)
raise errors.UserError(self.msg)
5 changes: 4 additions & 1 deletion conda_env/utils/uploader.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ def __init__(self, packagename, env_file, **kwargs):

@property
def version(self):
return time.strftime('%Y.%m.%d.%H%M')
if self.env_data and self.env_data.get('version'):
return self.env_data['version']
else:
return time.strftime('%Y.%m.%d.%H%M')

@property
def user(self):
Expand Down
8 changes: 4 additions & 4 deletions tests/specs/test_binstar.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def test_invalid_name(self):
self.assertEqual(spec.msg, "Invalid name, try the format: user/package")

def test_package_not_exist(self):
with patch('conda_env.specs.binstar.get_binstar') as get_binstar_mock:
with patch('conda_env.specs.binstar.get_server_api') as get_binstar_mock:
package = MagicMock(side_effect=errors.NotFound('msg'))
binstar = MagicMock(package=package)
get_binstar_mock.return_value = binstar
Expand All @@ -38,7 +38,7 @@ def test_package_not_exist(self):
self.assertEqual(spec.can_handle(), False)

def test_package_without_environment_file(self):
with patch('conda_env.specs.binstar.get_binstar') as get_binstar_mock:
with patch('conda_env.specs.binstar.get_server_api') as get_binstar_mock:
package = MagicMock(return_value={'files': []})
binstar = MagicMock(package=package)
get_binstar_mock.return_value = binstar
Expand All @@ -51,7 +51,7 @@ def test_download_environment(self):
'files': [{'type': 'env', 'version': '1', 'basename': 'environment.yml'}]
}
fake_req = MagicMock(text=u"name: env")
with patch('conda_env.specs.binstar.get_binstar') as get_binstar_mock:
with patch('conda_env.specs.binstar.get_server_api') as get_binstar_mock:
package = MagicMock(return_value=fake_package)
downloader = MagicMock(return_value=fake_req)
binstar = MagicMock(package=package, download=downloader)
Expand All @@ -69,7 +69,7 @@ def test_environment_version_sorting(self):
]
}
fake_req = MagicMock(text=u"name: env")
with patch('conda_env.specs.binstar.get_binstar') as get_binstar_mock:
with patch('conda_env.specs.binstar.get_server_api') as get_binstar_mock:
package = MagicMock(return_value=fake_package)
downloader = MagicMock(return_value=fake_req)
binstar = MagicMock(package=package, download=downloader)
Expand Down