Skip to content

Commit

Permalink
Merge 8a5c8c7 into 5a300ab
Browse files Browse the repository at this point in the history
  • Loading branch information
idomic committed Apr 26, 2022
2 parents 5a300ab + 8a5c8c7 commit 169e333
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 9 deletions.
44 changes: 42 additions & 2 deletions src/ploomber/cli/cloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,17 @@
import http.client as httplib
import click
from functools import wraps
import re

import humanize

from ploomber.exceptions import BaseException
from ploomber.telemetry import telemetry
from ploomber.telemetry.telemetry import parse_dag, UserSettings

CLOUD_APP_URL = 'ggeheljnx2.execute-api.us-east-1.amazonaws.com'
PIPELINES_RESOURCE = '/prod/pipelines'
CLOUD_APP_URL = 'api.ploomber.io'
PIPELINES_RESOURCE = '/pipelines'
EMAIL_RESOURCE = '/emailSignup'
headers = {'Content-type': 'application/json'}


Expand Down Expand Up @@ -236,3 +238,41 @@ def wrapper(*args, **kwargs):
return wrapper

return _cloud_call


def _get_input(text):
return input(text)


def _email_input():
# Validate that's the first email registration
settings = UserSettings()
if not settings.user_email:
email = _get_input(
"Our users enjoy updates, support and unique content "
"through email, please add your email, if you'd like "
"to register (type email): ")
_email_validation(email)


def _email_validation(email):
pattern = r"[^@]+@[^@]+\.[^@]+"
if re.match(pattern, email):
# Save in conf file
settings = UserSettings()
settings.user_email = email

# Call API
_email_registry(email)


def _email_registry(email):
conn = httplib.HTTPSConnection(CLOUD_APP_URL, timeout=3)
try:
user_headers = {'email': email, 'source': 'OS'}
conn.request("POST", EMAIL_RESOURCE, headers=user_headers)
print("Thanks for signing up!")
except httplib.HTTPException:
pass
finally:
conn.close()
2 changes: 2 additions & 0 deletions src/ploomber/cli/examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from ploomber.table import Table
from ploomber.telemetry import telemetry
from ploomber.exceptions import BaseException
from ploomber.cli.cloud import _email_input

from pygments.formatters.terminal import TerminalFormatter
from pygments.lexers.markup import MarkdownLexer
Expand Down Expand Up @@ -287,3 +288,4 @@ def main(name, force=False, branch=None, output=None):
f'\n$ ploomber install')
tw.write(f'\n\nOpen {str(path_to_readme)} for details.\n',
blue=True)
_email_input()
13 changes: 13 additions & 0 deletions src/ploomber/telemetry/telemetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class UserSettings(Config):
"""
version_check_enabled: bool = True
cloud_key: str = None
user_email: str = None
stats_enabled: bool = True

@classmethod
Expand Down Expand Up @@ -302,6 +303,16 @@ def is_cloud_user():
return settings.cloud_key


def email_registered():
"""
The function checks if the email is set for the user.
Checks if the user_email is set in the User conf file (config.yaml).
returns True/False accordingly.
"""
settings = UserSettings()
return settings.user_email


def check_version():
"""
The function checks if the user runs the latest version
Expand Down Expand Up @@ -395,6 +406,7 @@ def log_api(action, client_time=None, total_runtime=None, metadata=None):
py_version = python_version()
docker_container = is_docker()
cloud = is_cloud_user()
email = email_registered()
colab = is_colab()
if colab:
metadata['colab'] = colab
Expand Down Expand Up @@ -438,6 +450,7 @@ def log_api(action, client_time=None, total_runtime=None, metadata=None):
'ploomber_version': product_version,
'docker_container': docker_container,
'cloud': cloud,
'email': email,
'os': os,
'environment': environment,
'metadata': metadata,
Expand Down
70 changes: 69 additions & 1 deletion tests/cli/test_cloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import yaml
from click.testing import CliRunner

from ploomber.cli import cloud
from ploomber.cli import cloud, examples
from ploomber_cli.cli import get_key, set_key, write_pipeline, get_pipelines,\
delete_pipeline
from ploomber.telemetry import telemetry
Expand Down Expand Up @@ -387,3 +387,71 @@ def test_get_pipeline_with_dag(monkeypatch, mock_api_key):
# id = p['pipeline_id']
# res = cloud.delete_pipeline(id)
# assert id in str(res)


# Test empty string/emails without a @
@pytest.mark.parametrize('user_email', ['', 'test', '@', 'a@c'])
def test_malformed_email_signup(monkeypatch, user_email):
mock = Mock()
monkeypatch.setattr(cloud, '_email_registry', mock)

cloud._email_validation(user_email)
mock.assert_not_called()


# Testing valid api calls when the email is correct
def test_correct_email_signup(tmp_directory, monkeypatch):
monkeypatch.setattr(telemetry, 'DEFAULT_HOME_DIR', '.')
registry_mock = Mock()
monkeypatch.setattr(cloud, '_email_registry', registry_mock)

sample_email = 'test@example.com'
cloud._email_validation(sample_email)
registry_mock.assert_called_once()


# Test valid emails are stored in the user conf
def test_email_conf_file(tmp_directory, monkeypatch):
registry_mock = Mock()
monkeypatch.setattr(cloud, '_email_registry', registry_mock)
monkeypatch.setattr(telemetry, 'DEFAULT_HOME_DIR', '.')

stats = Path('stats')
stats.mkdir()
conf_path = stats / telemetry.DEFAULT_USER_CONF
conf_path.write_text("sample_conf_key: True\n")

sample_email = 'test@example.com'
cloud._email_validation(sample_email)

conf = conf_path.read_text()
assert sample_email in conf


def test_email_write_only_once(tmp_directory, monkeypatch):
monkeypatch.setattr(telemetry, 'DEFAULT_HOME_DIR', '.')
input_mock = Mock(return_value='some1@email.com')
monkeypatch.setattr(cloud, '_get_input', input_mock)
monkeypatch.setattr(telemetry.UserSettings, 'user_email', 'some@email.com')

cloud._email_input()
assert not input_mock.called


def test_email_call_on_examples(tmp_directory, monkeypatch):
email_mock = Mock()
monkeypatch.setattr(examples, '_email_input', email_mock)
examples.main(name=None, force=True)
email_mock.assert_called_once()


def test_email_called_once(tmp_directory, monkeypatch):
monkeypatch.setattr(telemetry, 'DEFAULT_HOME_DIR', '.')
email_mock = Mock(return_value='email@ploomber.io')
api_mock = Mock()
monkeypatch.setattr(cloud, '_get_input', email_mock)
monkeypatch.setattr(cloud, '_email_registry', api_mock)

examples.main(name=None, force=True)
examples.main(name=None, force=True)
email_mock.assert_called_once()
10 changes: 5 additions & 5 deletions tests/cli/test_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ def _mock_metadata(**kwargs):
return {**default, **kwargs}


@pytest.fixture(scope='session')
def clone_examples():
@pytest.fixture(scope='function')
def clone_examples(_mock_email):
examples.main(name=None, force=True)


Expand Down Expand Up @@ -101,7 +101,7 @@ def test_click_exception_isnt_shadowed_by_runtime_error(monkeypatch):
assert 'Error: some click exception\n' in result.output


def test_clones_in_home_directory(monkeypatch, tmp_directory):
def test_clones_in_home_directory(_mock_email, monkeypatch, tmp_directory):
# patch home directory
monkeypatch.setattr(examples, '_home', str(tmp_directory))

Expand All @@ -123,7 +123,7 @@ def test_clones_in_home_directory(monkeypatch, tmp_directory):
check=True)


def test_change_default_branch(monkeypatch, tmp_directory):
def test_change_default_branch(_mock_email, monkeypatch, tmp_directory):
# mock metadata to make it look older
metadata = _mock_metadata(timestamp=(datetime.now() -
timedelta(days=1)).timestamp())
Expand All @@ -149,7 +149,7 @@ def test_change_default_branch(monkeypatch, tmp_directory):


def test_does_not_download_again_if_no_explicit_branch_requested(
monkeypatch, tmp_directory):
_mock_email, monkeypatch, tmp_directory):
dir_ = Path(tmp_directory, 'examples')
monkeypatch.setattr(examples, '_home', dir_)

Expand Down
8 changes: 7 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from ploomber import Env
import pandas as pd
from glob import iglob
from ploomber.cli import install
from ploomber.cli import install, examples
import posthog
from unittest.mock import Mock, MagicMock

Expand Down Expand Up @@ -469,3 +469,9 @@ def tmp_imports(add_current_to_sys_path, no_sys_modules_cache):
test execution upon exit
"""
yield


@pytest.fixture
def _mock_email(monkeypatch):
examples_email_mock = Mock()
monkeypatch.setattr(examples, '_email_input', examples_email_mock)
1 change: 1 addition & 0 deletions tests/telemetry/test_telemetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ def test_user_settings_create_file(tmp_directory, monkeypatch):

assert content == {
'cloud_key': None,
'user_email': None,
'stats_enabled': True,
'version_check_enabled': True,
}
Expand Down

0 comments on commit 169e333

Please sign in to comment.