Example #1
0
 def _migration(attrs: Attrs) -> Attrs:
     roots = 'roots'
     if roots in attrs:  # legacy name
         attrs['paths'] = attrs[roots]
         from my.core.warnings import high
         high(f'"{roots}" is deprecated! Use "paths" instead.')
     return attrs
Example #2
0
def migration(attrs: Attrs) -> Attrs:
    export_dir = 'export_dir'
    if export_dir in attrs: # legacy name
        attrs['export_path'] = attrs[export_dir]
        from my.core.warnings import high
        high(f'"{export_dir}" is deprecated! Please use "export_path" instead."')
    return attrs
Example #3
0
def _fd_path() -> str:
    # todo move it to core
    fd_path: Optional[str] = shutil.which("fdfind") or shutil.which("fd-find") or shutil.which("fd")
    if fd_path is None:
        high(f"my.coding.commits requires 'fd' to be installed, See https://github.com/sharkdp/fd#installation")
    assert fd_path is not None
    return fd_path
Example #4
0
def repo(name: str) -> str:
    """
    e.g., converts to ~/Repos/name
    ~/Repos/ is where I store a lot of my git repositories
    """
    if "REPOS" in environ:
        return path.join(environ["REPOS"], name)
    else:
        high(
            r"Hey I use the $REPOS environment variable to determine where repositories are on my computer. If you have some directory you put those -- set something like 'export REPOS=~/projects' in your shell config. Otherwise, you can edit this 'def repo' function, or remove it from whatevers using it -- its probably some of my personal config"
        )
        return name
Example #5
0
def _locations() -> Iterator[Tuple[LatLon, datetime]]:
    try:
        import my.location.all
        for loc in my.location.all.locations():
            if loc.accuracy is not None and loc.accuracy > config.require_accuracy:
                continue
            yield ((loc.lat, loc.lon), loc.dt)

    except Exception as e:
        from my.core.warnings import high
        logger.exception(
            "Could not setup via_location using my.location.all provider, falling back to legacy google implemetation",
            exc_info=e)
        high(
            "Setup my.google.takeout.parser, then my.location.all for better google takeout/location data"
        )

        import my.location.google

        for gloc in my.location.google.locations():
            yield ((gloc.lat, gloc.lon), gloc.dt)
Example #6
0
def migration(attrs: Attrs) -> Attrs:
    # new structure, take top-level config and extract 'rexport' class
    # previously, 'rexport' key could be location of the rexport repo on disk
    if 'rexport' in attrs and not isinstance(attrs['rexport'], (str, Path)):
        ex: uconfig.rexport = attrs['rexport']
        attrs['export_path'] = ex.export_path
    else:
        from my.core.warnings import high
        high("""DEPRECATED! Please modify your reddit config to look like:

class reddit:
    class rexport:
        export_path: Paths = '/path/to/rexport/data'
            """)
        export_dir = 'export_dir'
        if export_dir in attrs:  # legacy name
            attrs['export_path'] = attrs[export_dir]
            high(
                f'"{export_dir}" is deprecated! Please use "export_path" instead."'
            )
    return attrs
Example #7
0
def _extract_locations(path: Path) -> Iterator[Res[Location]]:
    try:
        import gpxpy  # type: ignore[import]

        with path.open("r") as gf:
            gpx_obj = gpxpy.parse(gf)
            for track in gpx_obj.tracks:
                for segment in track.segments:
                    for point in segment.points:
                        # TODO: use elevation?
                        yield Location(
                            lat=point.latitude,
                            lng=point.longitude,
                            dt=datetime.replace(point.time,
                                                tzinfo=timezone.utc),
                        )
    except ImportError:
        high(
            "Should install 'gpxpy' to parse .gpx files, falling back to basic XML parsing"
        )
        yield from _extract_xml_locations(path)
Example #8
0
 def commited_dt(self) -> datetime:
     high(
         "DEPRECATED! Please replace 'commited_dt' with 'committed_dt' (two 't's instead of one)"
     )
     return self.committed_dt
Example #9
0
def config() -> commits_cfg:
    res = make_config(commits_cfg)
    if res.emails is None and res.names is None:
        # todo error policy? throw/warn/ignore
        high("Set either 'emails' or 'names', otherwise you'll get no commits")
    return res
Example #10
0
from typing import Iterator

from my.config import fbmessenger as user_config

import fbmessengerexport.dal as messenger

###
# support old style config
_new_section = getattr(user_config, 'fbmessengerexport', None)
_old_attr = getattr(user_config, 'export_db', None)

if _new_section is None and _old_attr is not None:
    from my.core.warnings import high
    high("""DEPRECATED! Please modify your fbmessenger config to look like:

class fbmessenger:
    class fbmessengerexport:
        export_db: PathIsh = '/path/to/fbmessengerexport/database'
            """)

    class fbmessengerexport:
        export_db = _old_attr

    setattr(user_config, 'fbmessengerexport', fbmessengerexport)
###

from ..core import PathIsh


@dataclass
class config(user_config.fbmessengerexport):
    export_db: PathIsh
Example #11
0
    # seems that when a submodule is imported, at some point it'll call some internal import machinery
    # with 'parent' set to the parent module
    # if parent module is imported first (i.e. in case of deprecated usage), it won't be the case
    args = inspect.getargvalues(f.frame)
    if args.locals.get('parent') == f'my.{mname}':
        imported_as_parent = True

    # this we can only detect from the code I guess
    line = '\n'.join(f.code_context or [])
    if re.match(rf'from\s+my\.{mname}\s+import\s+export', line):
        # todo 'export' is hardcoded, not sure how to infer allowed objects anutomatically..
        importing_submodule = True

legacy = not (imported_as_parent or importing_submodule)

if legacy:
    from my.core import warnings as W
    # TODO: add link to instructions to migrate
    W.high(
        "DEPRECATED! Instead of my.fbmessengerexport, import from my.fbmessengerexport.export"
    )
    # only import in legacy mode
    # otherswise might have unfortunate side effects (e.g. missing imports)
    from .export import *

# kinda annoying to keep it, but it's so legacy 'hpi module install my.fbmessenger' work
# needs to be on the top level (since it's extracted via ast module), but hopefully it doesn't hurt here
REQUIRES = [
    'git+https://github.com/karlicoss/fbmessengerexport',
]
Example #12
0
REQUIRES = [
    'git+https://github.com/karlicoss/rexport',
]

import re
import traceback

# some hacky traceback to inspect the current stack
# to see if the user is using the old style of importing
warn = False
for f in traceback.extract_stack():
    line = f.line or ''  # just in case it's None, who knows..

    # cover the most common ways of previously interacting with the module
    if 'import my.reddit ' in (line + ' '):
        warn = True
    elif 'from my import reddit' in line:
        warn = True
    elif re.match(
            r"from my\.reddit\simport\s(comments|saved|submissions|upvoted)",
            line):
        warn = True

# TODO: add link to instructions to migrate
if warn:
    from my.core import warnings as W
    W.high(
        "DEPRECATED! Instead of my.reddit, import from my.reddit.all instead.")

from .rexport import *
Example #13
0
from itertools import islice
from pathlib import Path
from subprocess import Popen, PIPE
from typing import Iterable, NamedTuple, Optional, Sequence, IO, Tuple
import re

# pip3 install geopy
import geopy  # type: ignore

from ..core.common import LazyLogger, mcachew
from ..core.cachew import cache_dir
from ..core import kompress

from my.core.warnings import high

high(
    "Please set up my.google.takeout.parser module for better takeout support")

# otherwise uses ijson
# todo move to config??
USE_GREP = False

logger = LazyLogger(__name__)


class Location(NamedTuple):
    dt: datetime
    lat: float
    lon: float
    alt: Optional[float]