def setgps(ctx, filename, lat, lon): """ Set GPS location for the image file. """ from pexif import JpegFile try: ef = JpegFile.fromFile(filename) ef.set_geo(float(lat), float(lon)) except IOError: type, value, traceback = sys.exc_info() print("Error opening file:", value) raise invoke.Exit(1) except JpegFile.InvalidFile: type, value, traceback = sys.exc_info() print("Error opening file:", value) raise invoke.Exit(2) try: ef.writeFile(filename) except IOError: type, value, traceback = sys.exc_info() print("Error saving file:", value) raise invoke.Exit(3)
def file_exists(ctx, path): """ Exit with code 0 if a the provided path exists and is a file, overwise exit with code 1. """ if not os.path.isfile(path): raise invoke.Exit(code=1)
def publish_release(ctx, version, user, pypi_name): """Publishes a package previously created by the 'pre_release' command.""" from git import Repo repo = Repo('.') tag_names = [x.name for x in repo.tags] if version not in tag_names: print('Could not find tag for version {}, exiting...'.format(version)) raise invoke.Exit(code=2) check_call(['devpi', 'use', 'https://devpi.net/{}/dev'.format(user)]) check_call(['devpi', 'push', 'pytest=={}'.format(version), 'pypi:{}'.format(pypi_name)]) check_call(['git', 'push', '[email protected]:pytest-dev/pytest.git', version]) emails = [ '*****@*****.**', '*****@*****.**' ] if version.endswith('.0'): emails.append('*****@*****.**') print('Version {} has been published to PyPI!'.format(version)) print() print('Please send an email announcement with the contents from:') print() print(' doc/en/announce/release-{}.rst'.format(version)) print() print('To the following mail lists:') print() print(' ', ','.join(emails)) print() print('And announce it on twitter adding the #pytest hash tag.')
def type_coverage(ctx): """ Check total type-hint coverage compared to `develop`. """ try: check_type_hint_coverage.main() except AssertionError as err: raise invoke.Exit(message=str(err), code=1)
def docker(ctx, build=False, run=False, tag="covid-tracker-api:latest", name=f"covid-api-{random.randint(0,999)}"): """Build and run docker container.""" if not any([build, run]): raise invoke.Exit(message="Specify either --build or --run", code=1) if build: docker_cmds = ["build", "."] else: docker_cmds = ["run", "--publish", "80", "--name", name] ctx.run(" ".join(["docker", *docker_cmds, "-t", tag]))
def svgtostencil(ctx, svg_path): """ Converts a SVG file to a stencil file compatible with mxGraph, output is printed in standard output. """ qmxgraph_scripts = os.path.join(os.getcwd(), 'scripts') import subprocess svg_to_stencil_script = os.path.join(qmxgraph_scripts, 'svg_to_stencil.py') raise invoke.Exit( subprocess.call(['python', svg_to_stencil_script, svg_path]))
def build(ctx): lektor_cli_ctx = Context() lektor_cli_ctx.load_plugins() env = lektor_cli_ctx.get_env() pad = env.new_pad() # This is essentially `lektor build --output-path build`. with CliReporter(env, verbosity=0): builder = Builder(pad, OUTPUT_DIR) failures = builder.build_all() if failures: raise invoke.Exit('Builder failed.')
def load(cls) -> None: try: fabfile_config = configparser.ConfigParser() fabfile_config.read('fabfile.cfg') cls.host = fabfile_config.get('Fabric', 'Host') cls.user = fabfile_config.get('Fabric', 'User') cls.key_filename = os.path.expanduser( fabfile_config.get('Fabric', 'KeyFilename')) cls.project_name = fabfile_config.get('Fabric', 'ProjectName') cls.project_path = fabfile_config.get('Fabric', 'ProjectPath') except configparser.Error as error: raise invoke.Exit(message=f'Config error: {error}', code=1)
def docs(ctx, python_version=None): """ Create the documentation html locally. """ import json import subprocess import tempfile from pathlib import Path conda_info_json = subprocess.check_output(['conda', 'info', '--json']) conda_info = json.loads(conda_info_json) current_env_name = conda_info["active_prefix_name"] if current_env_name in (None, 'base'): raise invoke.Exit("Activate the project's conda environment first") else: docs_env_name = f'{current_env_name}-docs' new_environ = os.environ.copy() new_environ['TEST_QMXGRAPH'] = '0' if python_version is not None: new_environ['PYTHON_VERSION'] = python_version script = [ '', # To have a new line at the start (see windows new line). f'conda devenv --name {docs_env_name} --file docs_environment.devenv.yml', f'conda activate {docs_env_name}', 'cd docs', 'sphinx-build . _build -W', ] if sys.platform == 'win32': suffix = '.bat' new_line = '\n@echo on\ncall ' command = ['cmd', '/C'] else: suffix = '.bash' new_line = '\n' command = ['bash', '-x'] script_file = tempfile.NamedTemporaryFile(suffix=suffix, delete=False) try: script_file.close() script_file = Path(script_file.name) script_file.write_text(new_line.join(script)) command.append(str(script_file)) subprocess.check_call(command, env=new_environ) finally: script_file.unlink()
def make_tag(ctx, version): """Create a new, local tag for the release, only if the repository is clean.""" from git import Repo repo = Repo(".") if repo.is_dirty(): print("Current repository is dirty. Please commit any changes and try again.") raise invoke.Exit(code=2) tag_names = [x.name for x in repo.tags] if version in tag_names: print("[generate.make_tag] Delete existing tag {}".format(version)) repo.delete_tag(version) print("[generate.make_tag] Create tag {}".format(version)) repo.create_tag(version)
def build(ctx, bust=False): lektor_cli_ctx = Context() if bust: project = lektor_cli_ctx.get_project() shutil.rmtree(project.get_package_cache_path(), ignore_errors=True) shutil.rmtree(project.get_output_path(), ignore_errors=True) lektor_cli_ctx.load_plugins() env = lektor_cli_ctx.get_env() pad = env.new_pad() # This is essentially `lektor build --output-path build`. with CliReporter(env, verbosity=0): builder = Builder(pad, OUTPUT_DIR) failures = builder.build_all() if failures: raise invoke.Exit('Builder failed.') # Generate redirect file. redirect_filename = os.path.join(OUTPUT_DIR, '_redirects') with io.open(redirect_filename, mode='w', encoding='utf8') as f: static_redirect = get_static_redirect() f.write(static_redirect) if not static_redirect.endswith('\n'): f.write('\n') f.write('\n') f.write('# Blog posts.\n') f.write('\n'.join(generate_blog_post_redirects(pad))) f.write('\n') f.write('\n') f.write('# Download redirects.\n') f.write('\n'.join(generate_download_redirects(pad))) f.write('\n') latest_redirect = get_latest_download_redirect(pad) if latest_redirect is not None: f.write('\n') f.write('# Latests version download links.\n') f.write(latest_redirect) f.write('\n')
def type_check(ctx, packages, install_types=False, show_default_packages=False): """Run mypy static type-checking on select packages.""" if show_default_packages: # Use this to keep the Type-checking section of the docs up to date. # https://docs.greatexpectations.io/docs/contributing/style_guides/code_style#type-checking print("\n".join(DEFAULT_PACKAGES_TO_TYPE_CHECK)) raise invoke.Exit(code=0) packages = packages or DEFAULT_PACKAGES_TO_TYPE_CHECK # once we have sunsetted `type-coverage` and our typing has matured we should define # our packages to exclude (if any) in the mypy config file. # https://mypy.readthedocs.io/en/stable/config_file.html#confval-exclude ge_pkgs = [f"great_expectations/{p}" for p in packages] cmds = [ "mypy", *ge_pkgs, ] if install_types: cmds.extend(["--install-types", "--non-interactive"]) ctx.run(" ".join(cmds), echo=True)
def linting(ctx): print_message('lint'.format(), color=Fore.BLUE, bright=True) cmd = 'flake8 -v qmxgraph' import subprocess raise invoke.Exit(subprocess.call(cmd, shell=True))
def newpost(ctx, title, slug=None, add_gpx=False, description=None, date=None): """ Prepare to add a new post. """ def slugify(s): s = s.lower() for c in [' ', '-', '.', '/']: s = s.replace(c, '_') s = re.sub('\W', '', s) s = s.replace('_', ' ') s = re.sub('\s+', ' ', s) s = s.strip() s = s.replace(' ', '-') return s # slug for the post post_slug = slug if slug is not None else slugify(title) print('Creating new post:') print(' title:', title) print(' slug:', post_slug) print(' add_gpx:', add_gpx) print(' description:', description) print(' date:', date) # check the branch and switch to a new one # 1. do a status and fetch invoke.run('git status') invoke.run("git fetch") # 2. check we are on master git_status = subprocess.check_output('git status', universal_newlines=True, shell=True) if 'On branch master' not in git_status: print("Error: should be starting from master") raise invoke.Exit(1) # 3. check up to date if 'Your branch is behind' in git_status: print("Error: branch is behind") raise invoke.Exit(1) # 4. create new branch invoke.run("git checkout -b %s" % post_slug) # directory for the content content_dir = os.path.join(ROOT_DIR, "content") post_dir = os.path.join(content_dir, post_slug) if os.path.exists(post_dir): print("Error: post directory already exists: %s" % post_dir) raise invoke.Exit(1) os.mkdir(post_dir) # content content_dict = { 'title': title, 'today': datetime.datetime.today().strftime('%Y-%m-%d'), 'gpx_file': post_slug + '.gpx' if add_gpx else '', 'description': '' if description is None else description, 'date': '' if date is None else date, } # content file content_file = os.path.join(post_dir, "contents.lr") templ = """title: %(title)s --- date: %(date)s --- pub_date: %(today)s --- author: Chris Scott --- image: --- latitude: --- longitude: --- gpx: %(gpx_file)s --- description: %(description)s --- body: """ % content_dict with open(content_file, "w") as fh: fh.write(templ)
def coverage(ctx, ): print_message('coverage'.format(), color=Fore.BLUE, bright=True) cmd = 'py.test --cov=qmxgraph -n auto --timeout=10' import subprocess raise invoke.Exit(subprocess.call(cmd, shell=True))
def test(ctx, ): print_message('test'.format(), color=Fore.BLUE, bright=True) cmd = 'py.test -n auto --timeout=10' import subprocess raise invoke.Exit(subprocess.call(cmd, shell=True))
def test(ctx): print_message('test'.format(), color=Fore.BLUE, bright=True) cmd = 'pytest --cov=qmxgraph --timeout=10 -v --durations=10' import subprocess raise invoke.Exit(subprocess.call(cmd, shell=True))