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

Commit

Permalink
Merge pull request #344 from dephell/win
Browse files Browse the repository at this point in the history
Windows support: make some dependencies optional, fix some paths
  • Loading branch information
orsinium committed Dec 20, 2019
2 parents 3117ca3 + 656dc2d commit 17d5604
Show file tree
Hide file tree
Showing 21 changed files with 165 additions and 129 deletions.
25 changes: 17 additions & 8 deletions dephell/actions/_transform.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
from typing import TYPE_CHECKING

# external
from bowler import LN, Capture, Filename, Query
from bowler.helpers import dotted_parts, power_parts, quoted_parts
from fissix.fixer_util import Dot, Name, syms
from fissix.pytree import Node


if TYPE_CHECKING:
from bowler import LN, Capture, Filename, Query

try:
from bowler.helpers import dotted_parts, power_parts, quoted_parts
except ImportError:
pass


modifiers = []


Expand All @@ -13,7 +22,7 @@ def _register(modifier):
return modifier


def transform_imports(query: Query, old_name: str, new_name: str) -> Query:
def transform_imports(query: 'Query', old_name: str, new_name: str) -> 'Query':
params = dict(
name=old_name,
dotted_name=' '.join(quoted_parts(old_name)),
Expand Down Expand Up @@ -46,7 +55,7 @@ def __init__(self, old_name, new_name):
self.old_name = old_name
self.new_name = new_name

def __call__(self, node: LN, capture: Capture, filename: Filename) -> None:
def __call__(self, node: 'LN', capture: 'Capture', filename: 'Filename') -> None:
old_node = capture['module_name']
new_node = Node(
type=syms.dotted_as_name,
Expand Down Expand Up @@ -83,7 +92,7 @@ def __init__(self, old_name, new_name):
self.old_name = old_name
self.new_name = new_name

def __call__(self, node: LN, capture: Capture, filename: Filename) -> None:
def __call__(self, node: 'LN', capture: 'Capture', filename: 'Filename') -> None:
new_name_node = build_new_name_node(
old_node=capture['module_name'],
new_name=self.new_name,
Expand Down Expand Up @@ -130,7 +139,7 @@ def __init__(self, old_name, new_name):
self.old_name = old_name
self.new_name = new_name

def __call__(self, node: LN, capture: Capture, filename: Filename) -> None:
def __call__(self, node: 'LN', capture: 'Capture', filename: 'Filename') -> None:
new_name_node = build_new_name_node(
old_node=capture['module_name'],
new_name=self.new_name,
Expand All @@ -153,7 +162,7 @@ def __init__(self, old_name, new_name):
self.old_name = old_name
self.new_name = new_name

def __call__(self, node: LN, capture: Capture, filename: Filename) -> None:
def __call__(self, node: 'LN', capture: 'Capture', filename: 'Filename') -> None:
if not self._capture(capture['string'].value):
return

Expand Down Expand Up @@ -190,7 +199,7 @@ def __init__(self, old_name, new_name):
self.old_name = old_name
self.new_name = new_name

def __call__(self, node: LN, capture: Capture, filename: Filename) -> None:
def __call__(self, node: 'LN', capture: 'Capture', filename: 'Filename') -> None:
if node.type == syms.power:
self._modify_power(node)
else:
Expand Down
2 changes: 1 addition & 1 deletion dephell/commands/generate_contributing.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,6 @@ def __call__(self) -> bool:
config = dict(config['tool']['dephell'])
project_path = Path(self.config['project'])
text = make_contributing(config=config, project_path=project_path)
(project_path / self.file_name).write_text(text)
(project_path / self.file_name).write_text(text, encoding='utf8')
self.logger.info('generated', extra=dict(file=self.file_name))
return True
11 changes: 8 additions & 3 deletions dephell/commands/vendor_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@
from argparse import ArgumentParser
from pathlib import Path

# external
from bowler import Query

# app
from ..actions import transform_imports
from ..config import builders
from .base import BaseCommand


try:
from bowler import Query
except ImportError:
Query = None


class VendorImportCommand(BaseCommand):
"""Patch all imports in project to use vendored dependencies.
"""
Expand All @@ -25,6 +28,8 @@ def build_parser(parser) -> ArgumentParser:
return parser

def __call__(self) -> bool:
if Query is None:
raise RuntimeError('vendorization is unsupported on Windows')
resolver = self._get_locked()
if resolver is None:
return False
Expand Down
9 changes: 8 additions & 1 deletion dephell/controllers/_docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,19 @@
# external
import attr
import docker
import dockerpty
from dephell_venvs import VEnvs

# app
from ..cached_property import cached_property
from ..networking import requests_session


try:
import dockerpty
except ImportError:
dockerpty = None


DOCKER_PREFIX = 'dephell-'


Expand Down Expand Up @@ -152,6 +157,8 @@ def activate(self) -> None:
return self.run(['sh', '-c', 'zsh || bash || sh'])

def run(self, command: List[str]) -> None:
if dockerpty is None:
raise RuntimeError('cannot run Docker on Windows')
self.container.start()
dockerpty.exec_command(
client=self.client.api,
Expand Down
44 changes: 23 additions & 21 deletions dephell/controllers/_repos.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,29 +41,31 @@ class RepositoriesRegistry(WarehouseBaseRepo):
propagate = True

def add_repo(self, *, url: str, name: str = None, from_config: bool = False) -> bool:
# try to interpret URL as local path
if url in self._urls:
return False
path = Path(url)
if path.exists():
if name is None:
name = path.name
if name in self._names:
return False
full_path = str(path.resolve())
if full_path in self._urls:
return False
self._names.add(name)
self._urls.update({url, full_path})
self.repos.append(WarehouseLocalRepo(
name=name,
path=path,
prereleases=self.prereleases,
from_config=from_config,
))
return True
elif '.' not in url:
raise FileNotFoundError('cannot find directory: {}'.format(url))

# try to interpret URL as local path
if '://' not in url:
path = Path(url)
if path.exists():
if name is None:
name = path.name
if name in self._names:
return False
full_path = str(path.resolve())
if full_path in self._urls:
return False
self._names.add(name)
self._urls.update({url, full_path})
self.repos.append(WarehouseLocalRepo(
name=name,
path=path,
prereleases=self.prereleases,
from_config=from_config,
))
return True
if '.' not in url and 'localhost' not in url:
raise FileNotFoundError('cannot find directory: {}'.format(url))

if not urlparse(url).scheme:
url = 'https://' + url
Expand Down
3 changes: 2 additions & 1 deletion dephell/converters/egginfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,8 @@ def dump(self, reqs, path: Path, project: RootDependency) -> None:

(path / 'dependency_links.txt').write_text(self.make_dependency_links(reqs=reqs))
(path / 'entry_points.txt').write_text(self.make_entrypoints(project=project))
(path / 'PKG-INFO').write_text(self.make_info(reqs=reqs, project=project, with_requires=False))
(path / 'PKG-INFO').write_text(self.make_info(reqs=reqs, project=project, with_requires=False),
encoding='utf8')
(path / 'requires.txt').write_text(self.make_requires(reqs=reqs))
(path / 'SOURCES.txt').write_text(self.make_sources(project=project))
(path / 'top_level.txt').write_text(self.make_top_level(project=project))
Expand Down
2 changes: 1 addition & 1 deletion dephell/converters/wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def load_dir(self, path) -> RootDependency:
urls = converter.parse_dependency_links(content)

# METADATA
with (path / 'METADATA').open('r') as stream:
with (path / 'METADATA').open('r', encoding='utf8') as stream:
content = stream.read()
root = converter.parse_info(content, urls=urls)

Expand Down
8 changes: 7 additions & 1 deletion tests/test_actions/test_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,18 @@

# external
import pytest
from bowler import Query

# project
from dephell.actions import transform_imports


try:
from bowler import Query
except ImportError:
Query = None


@pytest.mark.skipif(Query is None, reason='unsupported on windows')
@pytest.mark.parametrize('code_in, code_out, old_name, new_name', [
# module import
('import astana', 'import nursultan as astana', 'astana', 'nursultan'),
Expand Down
3 changes: 3 additions & 0 deletions tests/test_commands/test_vendor_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@
from pathlib import Path

# external
import pytest
from dephell_discover import Root as PackageRoot

# project
from dephell.commands import VendorImportCommand
from dephell.config import Config
from dephell.constants import IS_WINDOWS
from dephell.controllers import Graph, Mutator, Resolver
from dephell.models import RootDependency


@pytest.mark.skipif(IS_WINDOWS, reason='unsupported on windows')
def test_patch_imports(temp_path: Path):
(temp_path / 'project').mkdir()
(temp_path / 'project' / '__init__.py').write_text('import requests\nimport django')
Expand Down
4 changes: 2 additions & 2 deletions tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
from dephell.config import Config


def test_load():
def test_load(requirements_path: Path):
config = Config()
config.attach_file(path=str(Path('tests') / 'requirements' / 'dephell.toml'), env='some_env')
config.attach_file(path=str(requirements_path / 'dephell.toml'), env='some_env')
assert config['from']['format'] == 'pip'


Expand Down
63 changes: 33 additions & 30 deletions tests/test_converters/test_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,26 @@
from dephell.models import Requirement, RootDependency


root_path = Path(__file__).parent.parent / 'requirements'


@pytest.mark.allow_hosts()
@pytest.mark.parametrize('converter, path', [
(converters.PIPConverter(lock=False), Path('tests') / 'requirements' / 'attrs-requests.txt'),
(converters.PIPConverter(lock=False), Path('tests') / 'requirements' / 'django-deal.txt'),
(converters.PIPConverter(lock=False), Path('tests') / 'requirements' / 'scipy-pandas-numpy.txt'),
(converters.PIPConverter(lock=False), root_path / 'attrs-requests.txt'),
(converters.PIPConverter(lock=False), root_path / 'django-deal.txt'),
(converters.PIPConverter(lock=False), root_path / 'scipy-pandas-numpy.txt'),
(converters.PIPFileConverter(), Path('tests') / 'requirements' / 'pipfile.toml'),
(converters.PIPFileLockConverter(), Path('tests') / 'requirements' / 'pipfile.lock.json'),
(converters.PIPFileConverter(), root_path / 'pipfile.toml'),
(converters.PIPFileLockConverter(), root_path / 'pipfile.lock.json'),
(converters.FlitConverter(), Path('tests') / 'requirements' / 'flit.toml'),
(converters.FlitConverter(), root_path / 'flit.toml'),
(converters.PoetryConverter(), Path('tests') / 'requirements' / 'poetry.toml'),
(converters.PoetryLockConverter(), Path('tests') / 'requirements' / 'poetry.lock.toml'),
(converters.PoetryConverter(), root_path / 'poetry.toml'),
(converters.PoetryLockConverter(), root_path / 'poetry.lock.toml'),
(converters.SetupPyConverter(), Path('tests') / 'requirements' / 'setup.py'),
(converters.EggInfoConverter(), Path('tests') / 'requirements' / 'egg-info'),
(converters.WheelConverter(), Path('tests') / 'requirements' / 'wheel.whl'),
(converters.SetupPyConverter(), root_path / 'setup.py'),
(converters.EggInfoConverter(), root_path / 'egg-info'),
(converters.WheelConverter(), root_path / 'wheel.whl'),
])
def test_load_dump_load_deps(converter, path):
root1 = converter.load(path)
Expand Down Expand Up @@ -76,26 +79,26 @@ def test_load_dump_load_deps(converter, path):
@pytest.mark.parametrize('converter, path, exclude', [
(
converters.PIPFileConverter(),
Path('tests') / 'requirements' / 'pipfile.toml',
root_path / 'pipfile.toml',
['raw_name'],
),
(
converters.PIPFileLockConverter(),
Path('tests') / 'requirements' / 'pipfile.lock.json',
root_path / 'pipfile.lock.json',
['raw_name', 'python'],
),
(converters.FlitConverter(), Path('tests') / 'requirements' / 'flit.toml', []),
(converters.PoetryConverter(), Path('tests') / 'requirements' / 'poetry.toml', []),
(converters.PoetryLockConverter(), Path('tests') / 'requirements' / 'poetry.lock.toml', []),
(converters.SetupPyConverter(), Path('tests') / 'requirements' / 'setup.py', []),
(converters.FlitConverter(), root_path / 'flit.toml', []),
(converters.PoetryConverter(), root_path / 'poetry.toml', []),
(converters.PoetryLockConverter(), root_path / 'poetry.lock.toml', []),
(converters.SetupPyConverter(), root_path / 'setup.py', []),
(
converters.EggInfoConverter(),
Path('tests') / 'requirements' / 'egg-info',
root_path / 'egg-info',
['package', 'entrypoints', 'readme'],
),
(
converters.WheelConverter(),
Path('tests') / 'requirements' / 'wheel.whl',
root_path / 'wheel.whl',
['package', 'entrypoints'],
),
])
Expand All @@ -116,21 +119,21 @@ def test_load_dump_load_metainfo(converter, path, exclude):

@pytest.mark.allow_hosts()
@pytest.mark.parametrize('converter, path', [
(converters.PIPConverter(lock=False), Path('tests') / 'requirements' / 'attrs-requests.txt'),
(converters.PIPConverter(lock=False), Path('tests') / 'requirements' / 'django-deal.txt'),
(converters.PIPConverter(lock=False), Path('tests') / 'requirements' / 'scipy-pandas-numpy.txt'),
(converters.PIPConverter(lock=False), root_path / 'attrs-requests.txt'),
(converters.PIPConverter(lock=False), root_path / 'django-deal.txt'),
(converters.PIPConverter(lock=False), root_path / 'scipy-pandas-numpy.txt'),
(converters.PIPFileConverter(), Path('tests') / 'requirements' / 'pipfile.toml'),
(converters.PIPFileLockConverter(), Path('tests') / 'requirements' / 'pipfile.lock.json'),
(converters.PIPFileConverter(), root_path / 'pipfile.toml'),
(converters.PIPFileLockConverter(), root_path / 'pipfile.lock.json'),
(converters.FlitConverter(), Path('tests') / 'requirements' / 'flit.toml'),
(converters.FlitConverter(), root_path / 'flit.toml'),
(converters.PoetryConverter(), Path('tests') / 'requirements' / 'poetry.toml'),
# (converters.PoetryLockConverter(), Path('tests') / 'requirements' / 'poetry.lock.toml'),
(converters.PoetryConverter(), root_path / 'poetry.toml'),
# (converters.PoetryLockConverter(), root_path / 'poetry.lock.toml'),
(converters.SetupPyConverter(), Path('tests') / 'requirements' / 'setup.py'),
(converters.EggInfoConverter(), Path('tests') / 'requirements' / 'egg-info' / 'PKG-INFO'),
(converters.WheelConverter(), Path('tests') / 'requirements' / 'wheel.whl'),
(converters.SetupPyConverter(), root_path / 'setup.py'),
(converters.EggInfoConverter(), root_path / 'egg-info' / 'PKG-INFO'),
(converters.WheelConverter(), root_path / 'wheel.whl'),
])
def test_idempotency(converter, path):
root1 = converter.load(path)
Expand Down

0 comments on commit 17d5604

Please sign in to comment.