GithubHelp home page GithubHelp logo

gjcarneiro / yacron Goto Github PK

View Code? Open in Web Editor NEW
448.0 11.0 38.0 365 KB

A modern Cron replacement that is Docker-friendly

License: MIT License

Python 98.75% Dockerfile 0.95% Makefile 0.29%
cron yaml python asyncio docker

yacron's Introduction

Yet Another Cron

A modern Cron replacement that is Docker-friendly

  • Free software: MIT license

Features

  • "Crontab" is in YAML format;
  • Builtin sending of Sentry and Mail outputs when cron jobs fail;
  • Flexible configuration: you decide how to determine if a cron job fails or not;
  • Designed for running in Docker, Kubernetes, or 12 factor environments:
    • Runs in the foreground;
    • Logs everything to stdout/stderr [1];
  • Option to automatically retry failing cron jobs, with exponential backoff;
  • Optional HTTP REST API, to fetch status and start jobs on demand;
  • Arbitrary timezone support;
[1]Whereas vixie cron only logs to syslog, requiring a syslog daemon to be running in the background or else you don't get logs!

Status

The project is in beta stage: essential features are complete, and the focus is finding and fixing bugs before the first stable release.

Installation

Install using pip

yacron requires Python >= 3.6 (for systems with older Python, use the binary instead). It is advisable to install it in a Python virtual environment, for example:

python3 -m venv yacronenv
. yacronenv/bin/activate
pip install yacron

Install using pipx

pipx automates creating a virtualenv and installing a python program in the newly created virtualenv. It is as simple as:

pipx install yacron

Install using binary

Alternatively, a self-contained binary can be downloaded from github: https://github.com/gjcarneiro/yacron/releases. This binary should work on any Linux 64-bit system post glibc 2.23 (e.g. Ubuntu:16.04). Python is not required on the target system (it is embedded in the executable).

Usage

Configuration is in YAML format. To start yacron, give it a configuration file or directory path as the -c argument. For example:

yacron -c /tmp/my-crontab.yaml

This starts yacron (always in the foreground!), reading /tmp/my-crontab.yaml as configuration file. If the path is a directory, any *.yaml or *.yml files inside this directory are taken as configuration files.

Configuration basics

This configuration runs a command every 5 minutes:

jobs:
  - name: test-01
    command: echo "foobar"
    shell: /bin/bash
    schedule: "*/5 * * * *"

The command can be a string or a list of strings. If command is a string, yacron runs it through a shell, which is /bin/bash in the above example, but is /bin/sh by default.

If the command is a list of strings, the command is executed directly, without a shell. The ARGV of the command to execute is extracted directly from the configuration:

jobs:
  - name: test-01
    command:
      - echo
      - foobar
    schedule: "*/5 * * * *"

The schedule option can be a string in a crontab format specified by https://github.com/josiahcarlson/parse-crontab (this module is used by yacron). Additionally @reboot can be included , which will only run the job when yacron is initially executed. Further schedule can be an object with properties. The following configuration runs a command every 5 minutes, but only on the specific date 2017-07-19, and doesn't run it in any other date:

jobs:
  - name: test-01
    command: echo "foobar"
    schedule:
      minute: "*/5"
      dayOfMonth: 19
      month: 7
      year: 2017
      dayOfWeek: "*"

Important: by default all time is interpreted to be in UTC, but you can request to use local time instead. For instance, the cron job below runs every day at 19h27 local time because of the utc: false option:

jobs:
  - name: test-01
    command: echo "hello"
    schedule: "27 19 * * *"
    utc: false
    captureStdout: true

Since Yacron version 0.11, you can also request that the schedule be interpreted in an arbitrary timezone, using the timezone attribute:

jobs:
  - name: test-01
    command: echo "hello"
    schedule: "27 19 * * *"
    timezone: America/Los_Angeles
    captureStdout: true

You can ask for environment variables to be defined for command execution:

jobs:
  - name: test-01
    command: echo "foobar"
    shell: /bin/bash
    schedule: "*/5 * * * *"
    environment:
      - key: PATH
        value: /bin:/usr/bin

You can also provide an environment file to define environments for command execution:

jobs:
  - name: test-01
    command: echo "foobar"
    shell: /bin/bash
    schedule: "*/5 * * * *"
    env_file: .env

The env file must be a list of KEY=VALUE pairs. Empty lines and lines starting with # will be ignored.

Variables declared in the environment option will override those found in the env_file.

Specifying defaults

There can be a special defaults section in the config. Any attributes defined in this section provide default values for cron jobs to inherit. Although cron jobs can still override the defaults, as needed:

defaults:
    environment:
      - key: PATH
        value: /bin:/usr/bin
    shell: /bin/bash
    utc: false
jobs:
  - name: test-01
    command: echo "foobar"  # runs with /bin/bash as shell
    schedule: "*/5 * * * *"
  - name: test-02  # runs with /bin/sh as shell
    command: echo "zbr"
    shell: /bin/sh
    schedule: "*/5 * * * *"

Note: if the configuration option is a directory and there are multiple configuration files in that directory, then the defaults section in each configuration file provides default options only for cron jobs inside that same file; the defaults have no effect beyond any individual YAML file.

Reporting

Yacron has builtin support for reporting jobs failure (more on that below) by email, Sentry and shell command (additional reporting methods might be added in the future):

- name: test-01
  command: |
    echo "hello" 1>&2
    sleep 1
    exit 10
  schedule:
    minute: "*/2"
  captureStderr: true
  onFailure:
    report:
      sentry:
        dsn:
          value: example
          # Alternatively:
          # fromFile: /etc/secrets/my-secret-dsn
          # fromEnvVar: SENTRY_DSN
        fingerprint:  # optional, since yacron 0.6
          - yacron
          - "{{ environment.HOSTNAME }}"
          - "{{ name }}"
        extra:
          foo: bar
          zbr: 123
        level: warning
        environment: production
      mail:
        from: [email protected]
        to: [email protected]
        smtpHost: 127.0.0.1
        # optional fields:
        username: "username1"  # set username and password to enable login
        password:
          value: example
          # Alternatively:
          # fromFile: /etc/secrets/my-secret-password
          # fromEnvVar: MAIL_PASSWORD
        tls: false  # set to true to enable TLS
        starttls: false  # set to true to enable StartTLS
      shell:
        shell: /bin/bash
        command: ...

Here, the onFailure object indicates that what to do when a job failure is detected. In this case we ask for it to be reported both to sentry and by sending an email.

The captureStderr: true part instructs yacron to capture output from the the program's standard error, so that it can be included in the report. We could also turn on standard output capturing via the captureStdout: true option. By default, yacron captures only standard error. If a cron job's standard error or standard output capturing is not enabled, these streams will simply write to the same standard output and standard error as yacron itself.

Both stdout and stderr stream lines are by default prefixed with [{job_name} {stream_name}], i.e. [test-01 stdout], if for any reason you need to change this, provide the option streamPrefix (new in version 0.16) with your own custom string.

- name: test-01
  command: echo "hello world"
  schedule:
    minute: "*/2"
  captureStdout: true
  streamPrefix: "[{job_name} job]"

In some cases, for instance when you're logging JSON objects you might want to completely get rid of the prefix altogether:

- name: test-01
  command: echo "hello world"
  schedule:
    minute: "*/2"
  captureStdout: true
  streamPrefix: ""

It is possible also to report job success, as well as failure, via the onSuccess option.

- name: test-01
  command: echo "hello world"
  schedule:
    minute: "*/2"
  captureStdout: true
  onSuccess:
    report:
      mail:
        from: [email protected]
        to: [email protected]
        smtpHost: 127.0.0.1

Since yacron 0.5, it is possible to customise the format of the report. For mail reporting, the option subject indicates what is the subject of the email, while body formats the email body. For Sentry reporting, there is only body. In all cases, the values of those options are strings that are processed by the jinja2 templating engine. The following variables are available in templating:

  • name(str): name of the cron job
  • success(bool): whether or not the cron job succeeded
  • stdout(str): standard output of the process
  • stderr(str): standard error of the process
  • exit_code(int): process exit code
  • command(str): cron job command
  • shell(str): cron job shell
  • environment(dict): subprocess environment variables

Example:

- name: test-01
  command: |
    echo "hello" 1>&2
    sleep 1
    exit 10
  schedule:
    minute: "*/2"
  captureStderr: true
  onFailure:
    report:
      mail:
        from: [email protected]
        to: [email protected]
        smtpHost: 127.0.0.1
        subject: Cron job '{{name}}' {% if success %}completed{% else %}failed{% endif %}
        body: |
          {{stderr}}
          (exit code: {{exit_code}})

The shell reporter (since yacron 0.13) executes a user given shell command in the specified shell. It passes all environment variables from the python executable and specifies some additional ones to inform about the state of the job:

  • YACRON_FAIL_REASON (str)
  • YACRON_FAILED ("1" or "0")
  • YACRON_JOB_NAME (str)
  • YACRON_JOB_COMMAND (str)
  • YACRON_JOB_SCHEDULE (str)
  • YACRON_RETCODE (str)
  • YACRON_STDERR (str)
  • YACRON_STDOUT (str)

A simple example configuration:

- name: test-01
  command: echo "foobar" && exit 123
  shell: /bin/bash
  schedule: "* * * * *"
  onFailure:
    report:
      shell:
        shell: /bin/bash
        command: echo "Error code $YACRON_RETCODE"

Since yacron 0.15, it is possible to send emails formatted as html, by adding the html: true property. For example, here the standard output of a shell command is captured and interpreted as html and placed in the email message:

- name: test-01
  command: echo "hello <b>world</b>"
  schedule: "@reboot"
  captureStdout: true
  onSuccess:
    report:
      mail:
        from: [email protected]
        to: [email protected], [email protected]
        html: true
        smtpHost: 127.0.0.1
        smtpPort: 1025
        subject: This is a cron job with html body

Metrics

Yacron has builtin support for writing job metrics to Statsd:

jobs:
  - name: test01
    command: echo "hello"
    schedule: "* * * * *"
    statsd:
      host: my-statsd.example.com
      port: 8125
      prefix: my.cron.jobs.prefix.test01

With this config Yacron will write the following metrics over UDP to the Statsd listening on my-statsd.example.com:8125:

my.cron.jobs.prefix.test01.start:1|g  # this one is sent when the job starts
my.cron.jobs.prefix.test01.stop:1|g   # the rest are sent when the job stops
my.cron.jobs.prefix.test01.success:1|g
my.cron.jobs.prefix.test01.duration:3|ms|@0.1

Handling failure

By default, yacron considers that a job has failed if either the process returns a non-zero code or if it generates output to standard error (and standard error capturing is enabled, of course).

You can instruct yacron how to determine if a job has failed or not via the failsWhen option:

failsWhen:
  producesStdout: false
  producesStderr: true
  nonzeroReturn: true
  always: false
producesStdout
If true, any captured standard output causes yacron to consider the job as failed. This is false by default.
producesStderr
If true, any captured standard error causes yacron to consider the job as failed. This is true by default.
nonzeroReturn
If true, if the job process returns a code other than zero causes yacron to consider the job as failed. This is true by default.
always
If true, if the job process exits that causes yacron to consider the job as failed. This is false by default.

It is possible to instruct yacron to retry failing cron jobs by adding a retry option inside onFailure:

- name: test-01
  command: |
    echo "hello" 1>&2
    sleep 1
    exit 10
  schedule:
    minute: "*/10"
  captureStderr: true
  onFailure:
    report:
      mail:
        from: [email protected]
        to: [email protected]
        smtpHost: 127.0.0.1
    retry:
      maximumRetries: 10
      initialDelay: 1
      maximumDelay: 30
      backoffMultiplier: 2

The above settings tell yacron to retry the job up to 10 times, with the delay between retries defined by an exponential backoff process: initially 1 second, doubling for every retry up to a maximum of 30 seconds. A value of -1 for maximumRetries will mean yacron will keep retrying forever, this is mostly useful with a schedule of "@reboot" to restart a long running process when it has failed.

If the cron job is expected to fail sometimes, you may wish to report only in the case the cron job ultimately fails after all retries and we give up on it. For that situation, you can use the onPermanentFailure option:

- name: test-01
  command: |
    echo "hello" 1>&2
    sleep 1
    exit 10
  schedule:
    minute: "*/10"
  captureStderr: true
  onFailure:
    retry:
      maximumRetries: 10
      initialDelay: 1
      maximumDelay: 30
      backoffMultiplier: 2
  onPermanentFailure:
    report:
      mail:
        from: [email protected]
        to: [email protected]
        smtpHost: 127.0.0.1

Concurrency

Sometimes it may happen that a cron job takes so long to execute that when the moment its next scheduled execution is reached a previous instance may still be running. How yacron handles this situation is controlled by the option concurrencyPolicy, which takes one of the following values:

Allow
allows concurrently running jobs (default)
Forbid
forbids concurrent runs, skipping next run if previous hasn’t finished yet
Replace
cancels currently running job and replaces it with a new one

Execution timeout

(new in version 0.4)

If you have a cron job that may possibly hang sometimes, you can instruct yacron to terminate the process after N seconds if it's still running by then, via the executionTimeout option. For example, the following cron job takes 2 seconds to complete, yacron will terminate it after 1 second:

- name: test-03
  command: |
    echo "starting..."
    sleep 2
    echo "all done."
  schedule:
    minute: "*"
  captureStderr: true
  executionTimeout: 1  # in seconds

When terminating a job, it is always a good idea to give that job process some time to terminate properly. For example, it may have opened a file, and even if you tell it to shutdown, the process may need a few seconds to flush buffers and avoid losing data.

On the other hand, there are times when programs are buggy and simply get stuck, refusing to terminate nicely no matter what. For this reason, yacron always checks if a process exited some time after being asked to do so. If it hasn't, it tries to forcefully kill the process. The option killTimeout option indicates how many seconds to wait for the process to gracefully terminate before killing it more forcefully. In Unix systems, we first send a SIGTERM, but if the process doesn't exit after killTimeout seconds (30 by default) then we send SIGKILL. For example, this cron job ignores SIGTERM, and so yacron will send it a SIGKILL after half a second:

- name: test-03
  command: |
    trap "echo '(ignoring SIGTERM)'" TERM
    echo "starting..."
    sleep 10
    echo "all done."
  schedule:
    minute: "*"
  captureStderr: true
  executionTimeout: 1
  killTimeout: 0.5

Change to another user/group

(new in version 0.11)

You can request that Yacron change to another user and/or group for a specific cron job. The field user indicates the user (uid or userame) under which the subprocess must be executed. The field group (gid or group name) indicates the group id. If only user is given, the group defaults to the main group of that user. Example:

- name: test-03
  command: id
  schedule:
    minute: "*"
  captureStderr: true
  user: www-data

Naturally, yacron must be running as root in order to have permissions to change to another user.

Remote web/HTTP interface

(new in version 0.10)

If you wish to remotely control yacron, you can optionally enable an HTTP REST interface, with the following configuration (example):

web:
  listen:
     - http://127.0.0.1:8080
     - unix:///tmp/yacron.sock

Now you have the following options to control it (using HTTPie as example):

Get the version of yacron:

$ http get http://127.0.0.1:8080/version
HTTP/1.1 200 OK
Content-Length: 22
Content-Type: text/plain; charset=utf-8
Date: Sun, 03 Nov 2019 19:48:15 GMT
Server: Python/3.7 aiohttp/3.6.2

0.10.0b3.dev7+g45bc4ce

Get the status of cron jobs:

$ http get http://127.0.0.1:8080/status
HTTP/1.1 200 OK
Content-Length: 104
Content-Type: text/plain; charset=utf-8
Date: Sun, 03 Nov 2019 19:44:45 GMT
Server: Python/3.7 aiohttp/3.6.2

test-01: scheduled (in 14 seconds)
test-02: scheduled (in 74 seconds)
test-03: scheduled (in 14 seconds)

You may also get status info in json format:

$ http get http://127.0.0.1:8080/status Accept:application/json
HTTP/1.1 200 OK
Content-Length: 206
Content-Type: application/json; charset=utf-8
Date: Sun, 03 Nov 2019 19:45:53 GMT
Server: Python/3.7 aiohttp/3.6.2

[
    {
        "job": "test-01",
        "scheduled_in": 6.16588,
        "status": "scheduled"
    },
    {
        "job": "test-02",
        "scheduled_in": 6.165787,
        "status": "scheduled"
    },
    {
        "job": "test-03",
        "scheduled_in": 6.165757,
        "status": "scheduled"
    }
]

Start a job right now:

Sometimes it's useful to start a cron job right now, even if it's not scheduled to run yet, for example for testing:

$ http post http://127.0.0.1:8080/jobs/test-02/start
HTTP/1.1 200 OK
Content-Length: 0
Content-Type: application/octet-stream
Date: Sun, 03 Nov 2019 19:50:20 GMT
Server: Python/3.7 aiohttp/3.6.2

Includes

(new in version 0.13)

You may have a use case where it's convenient to have multiple config files, and choose at runtime which one to use. In that case, it might be useful if you can put common definitions (such as defaults for reporting, shell, etc.) in a separate file, that is included by the other files.

To support this use case, it is possible to ask one config file to include another one, via the include directive. It takes a list of file names: those files will be parsed as configuration and merged in with this file.

Example, your main config file could be:

include:
  - _inc.yaml

jobs:

  - name: my job
    ...

And your included _inc.yaml file could contain some useful defaults:

defaults:
  shell: /bin/bash
  onPermanentFailure:
    report:
      sentry:
        ...

Custom logging

It's possible to provide a custom logging configuration, via the logging configuration section. For example, the following configuration displays log lines with an embedded timestamp for each message.

logging:
  # In the format of:
  # https://docs.python.org/3/library/logging.config.html#dictionary-schema-details
  version: 1
  disable_existing_loggers: false
  formatters:
    simple:
      format: '%(asctime)s [%(processName)s/%(threadName)s] %(levelname)s (%(name)s): %(message)s'
      datefmt: '%Y-%m-%d %H:%M:%S'
  handlers:
    console:
      class: logging.StreamHandler
      level: DEBUG
      formatter: simple
      stream: ext://sys.stdout
  root:
    level: INFO
    handlers:
      - console

Obscure configuration options

enabled: true|false (default true)

(new in yacron 0.18)

It is possible to disable a specific cron job by adding a enabled: false option. Jobs with enabled: false will simply be skipped, as if they aren't there, apart from validating the configuration.

jobs:
  - name: test-01
    enabled: false  # this cron job will not run until you change this to `true`
    command: echo "foobar"
    shell: /bin/bash
    schedule: "* * * * *"

yacron's People

Contributors

andreas-wittig avatar bradburyj avatar cclauss avatar crdoconnor avatar delirious-lettuce avatar dependabot[bot] avatar eelkeh avatar evanskinner avatar gjcarneiro avatar h2g2bob avatar hhergeth avatar ragboyjr avatar thatsed avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

yacron's Issues

Switch user

  • Yet Another Cron version: N/A
  • Python version: 3
  • Operating System: Ubuntu

Description

The native cron allow specify user. Any plans about this?

#<timing> <user> <command>
11 * * * * root /usr/lib/command

Exposing simple REST endpoint to report what will run

@gjcarneiro raising a question here since I don't know if there's a better place

In our environment, we find it highly desirable to be able to answer questions like "what is scheduled to run in X [unit of time]"? For a simple use case, consider yacron triggering a (presumably long-ish) action within a running process; so if we intend to redeploy the said process, we want to make sure no relevant actions are about to take place within 10 minutes or so.

Of course we can read and mentally parse the yaml config, but it's not very human-friendly activity and requires mental date/time arithmetics. Hence we've been contemplating exposing a very simple HTTP API that can be interrogated to get ordered list of (job, timestamp) tuples for all jobs scheduled to run X units of time from now.

Have you ever considered this kind of feature? Will you accept a PR for such feature?

Thanks!

Sentry: add a line to every report explaining why it is considered error

It came up that sometimes it can happen that (1) both stdout and stderr produce a lot of output (2) both are captured and included in the sentry body, (3) sentry truncates the body to 512 characters (4) a developer is left in the dark as to why that cron job was considered an error (since the stderr part of the cron job has been truncated away).

I am thinking a small line added by default at the top of each sentry message explaining why the cron job was considered an error would help.

Optional stream line prefix

  • Yet Another Cron version: 0.15.1
  • Python version: any
  • Operating System: any

Description

For logging purposes it would be great if we're able to change the prefix that's now prepended to all log lines (stdout/stderr). For example: We're logging JSON objects, but any parsing of them by log aggregators is broken by the prepending of "[{} {}] ".format(self.job_name, self.stream_name), if we're able to change this prefix (i.e. to an empty string), we would be able to stream our logs.

What I Did

Created an extra option (that yet needs needs to documented) called streamPrefix to optinally set the prefix where the current prefix is the default.
See PR #58

/etc/yacron.d is missing

  • Yet Another Cron version: yacron-0.17.0-x86_64-unknown-linux-gnu
  • Python version:
  • Operating System: Docker, Ubuntu-20

Description

If the yacron-0.17.0-x86_64-unknown-linux-gnu is run without any option it returns:
"ERROR:yacron:Configuration error: [Errno 2] No such file or directory: '/etc/yacron.d'"

There ist no info at all about /etc/yacron.d. What is expected there resp. what can be done there?

What I Did

./yacron-0.17.0-x86_64-unknown-linux-gnu

TypeError: main() missing 1 required positional argument: 'loop'

  • Yet Another Cron version: 0.4.1
  • Python version: 3.6.2
  • Operating System: Debian Jessie

Description

yacron executable is not working.

What I Did

$ pip install yacron
...
$ yacron -c /etc/crontab
Traceback (most recent call last):
  File "/usr/local/bin/yacron", line 11, in <module>
    sys.exit(main())
TypeError: main() missing 1 required positional argument: 'loop'

@reboot schedule breaks /status endpoint

  • Yet Another Cron version: 0.10.0
  • Python version: 3.7.1
  • Operating System: alpine linux (docker)

When there's a job with @reboot schedule, the /status endpoint fails with the following stack trace:

ERROR:aiohttp.server:Error handling request
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/aiohttp/web_protocol.py", line 418, in start
    resp = await task
  File "/usr/local/lib/python3.7/site-packages/aiohttp/web_app.py", line 458, in _handle
    resp = await handler(request)
  File "/usr/local/lib/python3.7/site-packages/yacron/cron.py", line 180, in _web_get_status
    "scheduled_in": crontab.next(default_utc=job.utc),
AttributeError: 'str' object has no attribute 'next'
INFO:aiohttp.access:172.17.0.1 [13/Dec/2019:01:14:01 +0000] "GET /status HTTP/1.1" 500 244 "-" "HTTPie/0.9.9"

Yacron HTTP server failing with: KeyError: "Key not found: 'Accept'"

  • Yet Another Cron version: 0.11.2
  • Python version: the one bundled on the tagged 0.11.2 on the release page
  • Operating System: debian-stable

Description

The web listen config fails to parse requests coming from the kubernetes health checks.

What I Did

The yacron config

web:
  listen:
    - http://0.0.0.0:8072

The kubernetes healt check config:

        readinessProbe:
          httpGet:
            path: /status
            port: 8072
            scheme: HTTP

The output logs:

INFO:aiohttp.access:10.101.111.72 [22/Apr/2021:16:35:57 +0000] "GET /status HTTP/1.1" 500 244 "-" "kube-probe/1.19"
ERROR:aiohttp.server:Error handling request
Traceback (most recent call last):
  File "aiohttp/web_protocol.py", line 418, in start
  File "aiohttp/web_app.py", line 458, in _handle
  File "yacron/cron.py", line 182, in _web_get_status
  File "multidict/_multidict_py.py", line 74, in __getitem__
  File "multidict/_multidict_py.py", line 69, in getone
KeyError: "Key not found: 'Accept'"

Apparently it doesn't know how to pare the Accept header or something.

Thanks team!

Reload config without restart

  • Yet Another Cron version: latest
  • Python version: latest
  • Operating System: Debian 10

Description

Can yacron reload configuration without restarting?
I want to deploy a new configuration and do not wait for yacron to stop and start again..
Because some script can run for several hours

LD_LIBRARY_PATH env var is breaking curl commands to HTTPS url

I'm not sure where this env var LD_LIBRARY_PATH is being set but it's causing issues with cURL HTTPS urls. I'm assuming via one of the app dependencies. It seems that curl will reference a certificate from that location but since it's stored in /tmp the certificate is deleted eventually and curl explodes. I'm hoping you might be able to shed some more light on this.

https://curl.se/mail/archive-2003-05/0081.html

Error:
curl: (77) error setting certificate verify locations:
CApath: /etc/ssl/certs
CAfile: /tmp/_MEI6rUB1Z/certifi/cacert.pem

root@6832c8922330:/# yacron -c yacron.yml 
INFO:yacron:Starting job test
INFO:yacron:Job test spawned
[test stdout] HOSTNAME=6832c8922330
[test stdout] SHLVL=1
[test stdout] LD_LIBRARY_PATH=/tmp/_MEI6rUB1Z
[test stdout] HOME=/root
[test stdout] SSL_CERT_FILE=/tmp/_MEI6rUB1Z/certifi/cacert.pem
[test stdout] _=/usr/local/bin/yacron
[test stdout] TERM=xterm
[test stdout] PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
[test stdout] DEBIAN_FRONTEND=noninteractive
[test stdout] PWD=/
INFO:yacron:Job test exit code 0; has stdout: true, has stderr: false; fail_reason: None
INFO:yacron:Cron job test: reporting success
^CINFO:yacron:Shutting down (after currently running jobs finish)...
root@6832c8922330:/# cat yacron.yml 
defaults:
  captureStderr: true
  captureStdout: true
  onFailure:
    report:
      sentry:
        dsn:
          fromEnvVar: SENTRY_DSN
  concurrencyPolicy: Forbid

jobs:
  - name: test
    command: env
    schedule: "* * * * *"
root@6832c8922330:/# 

Email / Sentry reporting: jinja2 templating

As a final feature before a 1.0 release, I'd would like to have the reports more customisable, using jinja2 as templating language. Namely, the "subject" and "body" of the reporting would have the possibility of being customised.

  onPermanentFailure:
    report:
      sentry:
         dsn:
           value: xxxxx
      title: "job {{name}} has failed"
      body: |
          The cron job {{name}} has failed with status {{status}}
          STDOUT:
          ------------
          {{stdout}}

          STDERR:
          ------------
          {{stderr}}

Sentry reporting is broken with yacron self-contained binary

  • Yet Another Cron version:
  • Python version: 0.10.0
  • Operating System: ubuntu 18.04
INFO:yacron:Starting job test-01
INFO:yacron:Job test-01 spawned
[test-01 stderr] hello
INFO:yacron:Job test-01 exit code 10; has stdout: false, has stderr: true; failed: true
INFO:yacron:Job test-01 STDERR:
hello
INFO:yacron:Cron job test-01: reporting failure
ERROR:yacron:Problem reporting job test-01 failure: name '__file__' is not defined

It seems that this is failing inside https://github.com/getsentry/sentry-python due to pyoxidizer binaries python modules not having __file__ attributes.

Handling of schedule-entries not clear enough documented

  • Yet Another Cron version: yacron-0.17.0-x86_64-unknown-linux-gnu
  • Python version: -
  • Operating System: Docker/Ubuntu

Description

It's supposed, that Yacron understands schedule expressions according the original cron - at least the documentation "sounds" so. But it isn't (most probably because yacron has it's own implementation).
The schedule schedule: "0 22 */100,1-7 * FRI" from https://blog.healthchecks.io/2022/09/schedule-cron-job-the-funky-way delivers

root@74e7ce8d1534:/opt/skripte/docker/yacron# ./yacron-0.17.0-x86_64-unknown-linux-gnu -c yacrontab.yaml
Traceback (most recent call last):
  File "yacron", line 3, in <module>
  File "yacron/__main__.py", line 56, in main
  File "yacron/__main__.py", line 31, in main_loop
  File "yacron/cron.py", line 82, in __init__
  File "yacron/cron.py", line 141, in update_config
  File "yacron/config.py", line 472, in parse_config
  File "yacron/config.py", line 435, in parse_config_file
  File "yacron/config.py", line 426, in parse_config_string
  File "yacron/config.py", line 275, in __init__
  File "crontab/_crontab.py", line 386, in __init__
  File "crontab/_crontab.py", line 408, in _make_matchers
  File "crontab/_crontab.py", line 408, in <listcomp>
  File "crontab/_crontab.py", line 204, in __init__
  File "crontab/_crontab.py", line 357, in _parse_crontab
  File "crontab/_crontab.py", line 181, in _assert
ValueError: increment value must be less than 31, you provided 100
[1994] Failed to execute script 'yacron' due to unhandled exception!

Besides the unhandled exception (not really a problem) the question arises: how to find out, which schedule expressions are valid and which are not valid. The common crontab-generators render useless; e.g. https://crontab.guru, https://www.bennetrichter.de/tools/crontab-generator

Since I don't know python: maybe one ore two reference sites can be linked in the Yacron-Doku, how schedules are handled resp. which schedules are valid?

executionTimeout and killTimeout not working

  • Yet Another Cron version: 0.17.0
  • Python version: 3.10
  • Operating System: Ubuntu 22

Description

Trying to use executionTimeout and killTimeout to handle a process that could possibly hang forever.

defaults:
  utc: false
  concurrencyPolicy: Forbid

jobs:
  - name: fetch_emails
    command: |
      sleep 999
    schedule: "* * * * *"
    captureStderr: true
    executionTimeout: 5
    killTimeout: 1

Expected: fetch_emails job should be terminated and a new one should be able to start.
Actual:

INFO:yacron:Starting job fetch_emails
INFO:yacron:Job fetch_emails spawned
INFO:yacron:Job fetch_emails exceeded its executionTimeout of 5.0 seconds, cancelling it...
WARNING:yacron:Job fetch_emails: still running and concurrencyPolicy is Forbid

task every45minutes unnecessary second start

yacron run inside docker alpine 3.6 based
python 3.6.1
timezone in the container and on the host is the same.

The report 'onSuccess' comes two times, 45 minutes and 15 minutes after that.
in other words, the task runs twice per hour

crontab.yaml

defaults:
  captureStderr: true
  captureStdout: true
  onFailure:
    report:
      mail:
        from: [email protected]
        to: [email protected]
        smtpHost: xxxxxxxx
        subject: Cron job '{{name}}' {% if success %}completed{% else %}failed{% endif %}
        body: |
          command: {{command}}
          shell: {{shell}}
          environment: {{environment}}
          STDOUT: {{stdout}}
          STDERR: {{stderr}}
          exit code: {{exit_code}}

jobs:
- name: 45minutes
  command: /usr/bin/php5 /xxx/xxx/xxx.php
#  schedule: "*/45 * * * *"
  schedule:
    minute: "*/45"
  onSuccess:
    report:
      mail:
        from: [email protected]
        to: [email protected]
        smtpHost: xxxxxxxx

Error while trying to run the Docker container

  • Yet Another Cron version: latest (0.7.0)
  • Python version: 3.6
  • Operating System: Ubuntu Xenial

Description

I have the files from https://github.com/gjcarneiro/yacron/tree/master/example/docker

What I Did

docker run -ti yacrondemo -l DEBUG # Ctrl-C to stop

I got this error

ERROR:yacron:Configuration error: while parsing a mapping
unexpected key not in schema 'captureStdout'
  in "/etc/yacron.d/yacrontab.yaml", line 10, column 1:
    captureStdout: 'true'
    ^ (line: 10)

Feature Request: Sentry environment config

  • Yet Another Cron version: 0.13.0
  • Python version: any
  • Operating System: any

Description

Sentry allows you to set the environment during the initialization, this is very helpful as allows later to easily filter on their UI errors for different environments we have.

Reference: https://docs.sentry.io/platforms/python/configuration/environments/

It would be great to be able to define this environment (optionally) on the yacron sentry config and used like explained on the link above.

Thanks a lot and great work on this project

Building yacron pyinstaller on newer python version fail

  • Yet Another Cron version: git master
  • Python version: 3.10, 3.11
  • Operating System: Dockerized python:3.10 & python:3.11

Description

Thanks for giving Dockerfile for binary release for yacron, i personally build it and use in other project, work gracefully. And now it failing when python:3.10 or 3.11 used.

What I Did

Building yacron binary dist with pyspec, with updated python version.

Latest known work

Python 3.9

Build Log

python 3.10 failed build ruamel.yml`

#20 13.16       running build_ext
#20 13.16       building '_ruamel_yaml' extension
#20 13.16       creating build/temp.linux-x86_64-cpython-310
#20 13.16       creating build/temp.linux-x86_64-cpython-310/ext
#20 13.16       gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/usr/local/include/python3.10 -c ext/_ruamel_yaml.c -o build/temp.linux-x86_64-cpython-310/ext/_ruamel_yaml.o
#20 13.16       In file included from ext/_ruamel_yaml.c:596:
#20 13.16       ext/_ruamel_yaml.h:10: warning: "PyString_CheckExact" redefined
#20 13.16          10 | #define PyString_CheckExact PyBytes_CheckExact
#20 13.16             |
#20 13.16       ext/_ruamel_yaml.c:486: note: this is the location of the previous definition
#20 13.16         486 |   #define PyString_CheckExact          PyUnicode_CheckExact
#20 13.16             |
#20 13.16       ext/_ruamel_yaml.c: In function ‘__pyx_pf_12_ruamel_yaml_get_version_string’:
#20 13.16       ext/_ruamel_yaml.c:1886:17: warning: assignment discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
#20 13.16        1886 |   __pyx_v_value = yaml_get_version_string();
#20 13.16             |                 ^
#20 13.16       ext/_ruamel_yaml.c: In function ‘__pyx_pf_12_ruamel_yaml_7CParser___init__’:
#20 13.16       ext/_ruamel_yaml.c:3386:52: warning: passing argument 2 of ‘yaml_parser_set_input’ from incompatible pointer type [-Wincompatible-pointer-types]
#20 13.16        3386 |     yaml_parser_set_input((&__pyx_v_self->parser), __pyx_f_12_ruamel_yaml_input_handler, ((void *)__pyx_v_self));
#20 13.16             |                                                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#20 13.16             |                                                    |
#20 13.16             |                                                    int (*)(void *, char *, int,  int *)
#20 13.16       In file included from ext/_ruamel_yaml.h:2,
#20 13.16                        from ext/_ruamel_yaml.c:596:
#20 13.16       ext/yaml.h:1370:30: note: expected ‘int (*)(void *, unsigned char *, size_t,  size_t *)’ {aka ‘int (*)(void *, unsigned char *, long unsigned int,  long unsigned int *)’} but argument is of type ‘int (*)(void *, char *, int,  int *)’
#20 13.16        1370 |         yaml_read_handler_t *handler, void *data);
#20 13.16             |         ~~~~~~~~~~~~~~~~~~~~~^~~~~~~
#20 13.16       In file included from /usr/local/include/python3.10/bytesobject.h:62,
#20 13.16                        from /usr/local/include/python3.10/Python.h:82,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/cpython/bytesobject.h:32:57: warning: pointer targets in passing argument 2 of ‘yaml_parser_set_input_string’ differ in signedness [-Wpointer-sign]
#20 13.16          32 | #define PyBytes_AS_STRING(op) (assert(PyBytes_Check(op)), \
#20 13.16             |                               ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~
#20 13.16             |                                                         |
#20 13.16             |                                                         char *
#20 13.16          33 |                                 (((PyBytesObject *)(op))->ob_sval))
#20 13.16             |                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#20 13.16       ext/_ruamel_yaml.h:11:29: note: in expansion of macro ‘PyBytes_AS_STRING’
#20 13.16          11 | #define PyString_AS_STRING  PyBytes_AS_STRING
#20 13.16             |                             ^~~~~~~~~~~~~~~~~
#20 13.16       ext/_ruamel_yaml.c:3627:59: note: in expansion of macro ‘PyString_AS_STRING’
#20 13.16        3627 |     yaml_parser_set_input_string((&__pyx_v_self->parser), PyString_AS_STRING(__pyx_v_stream), PyString_GET_SIZE(__pyx_v_stream));
#20 13.16             |                                                           ^~~~~~~~~~~~~~~~~~
#20 13.16       In file included from ext/_ruamel_yaml.h:2,
#20 13.16                        from ext/_ruamel_yaml.c:596:
#20 13.16       ext/yaml.h:1344:30: note: expected ‘const unsigned char *’ but argument is of type ‘char *’
#20 13.16        1344 |         const unsigned char *input, size_t size);
#20 13.16             |         ~~~~~~~~~~~~~~~~~~~~~^~~~~
#20 13.16       ext/_ruamel_yaml.c: In function ‘__pyx_f_12_ruamel_yaml_7CParser__token_to_object’:
#20 13.16       ext/_ruamel_yaml.c:5461:71: warning: pointer targets in passing argument 1 of ‘PyUnicode_FromString’ differ in signedness [-Wpointer-sign]
#20 13.16        5461 |     __pyx_t_2 = PyUnicode_FromString(__pyx_v_token->data.tag_directive.handle); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 416, __pyx_L1_error)
#20 13.16             |                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
#20 13.16             |                                                                       |
#20 13.16             |                                                                       yaml_char_t * {aka unsigned char *}
#20 13.16       In file included from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/unicodeobject.h:138:17: note: expected ‘const char *’ but argument is of type ‘yaml_char_t *’ {aka ‘unsigned char *’}
#20 13.16         138 |     const char *u              /* UTF-8 encoded string */
#20 13.16             |     ~~~~~~~~~~~~^
#20 13.16       ext/_ruamel_yaml.c:5473:71: warning: pointer targets in passing argument 1 of ‘PyUnicode_FromString’ differ in signedness [-Wpointer-sign]
#20 13.16        5473 |     __pyx_t_2 = PyUnicode_FromString(__pyx_v_token->data.tag_directive.prefix); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 417, __pyx_L1_error)
#20 13.16             |                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
#20 13.16             |                                                                       |
#20 13.16             |                                                                       yaml_char_t * {aka unsigned char *}
#20 13.16       In file included from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/unicodeobject.h:138:17: note: expected ‘const char *’ but argument is of type ‘yaml_char_t *’ {aka ‘unsigned char *’}
#20 13.16         138 |     const char *u              /* UTF-8 encoded string */
#20 13.16             |     ~~~~~~~~~~~~^
#20 13.16       ext/_ruamel_yaml.c:6475:63: warning: pointer targets in passing argument 1 of ‘PyUnicode_FromString’ differ in signedness [-Wpointer-sign]
#20 13.16        6475 |     __pyx_t_2 = PyUnicode_FromString(__pyx_v_token->data.alias.value); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 447, __pyx_L1_error)
#20 13.16             |                                      ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~
#20 13.16             |                                                               |
#20 13.16             |                                                               yaml_char_t * {aka unsigned char *}
#20 13.16       In file included from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/unicodeobject.h:138:17: note: expected ‘const char *’ but argument is of type ‘yaml_char_t *’ {aka ‘unsigned char *’}
#20 13.16         138 |     const char *u              /* UTF-8 encoded string */
#20 13.16             |     ~~~~~~~~~~~~^
#20 13.16       ext/_ruamel_yaml.c:6559:64: warning: pointer targets in passing argument 1 of ‘PyUnicode_FromString’ differ in signedness [-Wpointer-sign]
#20 13.16        6559 |     __pyx_t_2 = PyUnicode_FromString(__pyx_v_token->data.anchor.value); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 450, __pyx_L1_error)
#20 13.16             |                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~
#20 13.16             |                                                                |
#20 13.16             |                                                                yaml_char_t * {aka unsigned char *}
#20 13.16       In file included from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/unicodeobject.h:138:17: note: expected ‘const char *’ but argument is of type ‘yaml_char_t *’ {aka ‘unsigned char *’}
#20 13.16         138 |     const char *u              /* UTF-8 encoded string */
#20 13.16             |     ~~~~~~~~~~~~^
#20 13.16       ext/_ruamel_yaml.c:6643:61: warning: pointer targets in passing argument 1 of ‘PyUnicode_FromString’ differ in signedness [-Wpointer-sign]
#20 13.16        6643 |     __pyx_t_2 = PyUnicode_FromString(__pyx_v_token->data.tag.handle); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 453, __pyx_L1_error)
#20 13.16             |                                      ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
#20 13.16             |                                                             |
#20 13.16             |                                                             yaml_char_t * {aka unsigned char *}
#20 13.16       In file included from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/unicodeobject.h:138:17: note: expected ‘const char *’ but argument is of type ‘yaml_char_t *’ {aka ‘unsigned char *’}
#20 13.16         138 |     const char *u              /* UTF-8 encoded string */
#20 13.16             |     ~~~~~~~~~~~~^
#20 13.16       ext/_ruamel_yaml.c:6655:61: warning: pointer targets in passing argument 1 of ‘PyUnicode_FromString’ differ in signedness [-Wpointer-sign]
#20 13.16        6655 |     __pyx_t_2 = PyUnicode_FromString(__pyx_v_token->data.tag.suffix); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 454, __pyx_L1_error)
#20 13.16             |                                      ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
#20 13.16             |                                                             |
#20 13.16             |                                                             yaml_char_t * {aka unsigned char *}
#20 13.16       In file included from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/unicodeobject.h:138:17: note: expected ‘const char *’ but argument is of type ‘yaml_char_t *’ {aka ‘unsigned char *’}
#20 13.16         138 |     const char *u              /* UTF-8 encoded string */
#20 13.16             |     ~~~~~~~~~~~~^
#20 13.16       ext/_ruamel_yaml.c:6779:64: warning: pointer targets in passing argument 1 of ‘PyUnicode_DecodeUTF8’ differ in signedness [-Wpointer-sign]
#20 13.16        6779 |     __pyx_t_2 = PyUnicode_DecodeUTF8(__pyx_v_token->data.scalar.value, __pyx_v_token->data.scalar.length, ((char *)"strict")); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 459, __pyx_L1_error)
#20 13.16             |                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~
#20 13.16             |                                                                |
#20 13.16             |                                                                yaml_char_t * {aka unsigned char *}
#20 13.16       In file included from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/unicodeobject.h:455:17: note: expected ‘const char *’ but argument is of type ‘yaml_char_t *’ {aka ‘unsigned char *’}
#20 13.16         455 |     const char *string,         /* UTF-8 encoded string */
#20 13.16             |     ~~~~~~~~~~~~^~~~~~
#20 13.16       ext/_ruamel_yaml.c: In function ‘__pyx_f_12_ruamel_yaml_7CParser__event_to_object’:
#20 13.16       ext/_ruamel_yaml.c:8460:63: warning: pointer targets in passing argument 1 of ‘PyUnicode_FromString’ differ in signedness [-Wpointer-sign]
#20 13.16        8460 |         __pyx_t_4 = PyUnicode_FromString(__pyx_v_tag_directive->handle); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 573, __pyx_L1_error)
#20 13.16             |                                          ~~~~~~~~~~~~~~~~~~~~~^~~~~~~~
#20 13.16             |                                                               |
#20 13.16             |                                                               yaml_char_t * {aka unsigned char *}
#20 13.16       In file included from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/unicodeobject.h:138:17: note: expected ‘const char *’ but argument is of type ‘yaml_char_t *’ {aka ‘unsigned char *’}
#20 13.16         138 |     const char *u              /* UTF-8 encoded string */
#20 13.16             |     ~~~~~~~~~~~~^
#20 13.16       ext/_ruamel_yaml.c:8472:63: warning: pointer targets in passing argument 1 of ‘PyUnicode_FromString’ differ in signedness [-Wpointer-sign]
#20 13.16        8472 |         __pyx_t_4 = PyUnicode_FromString(__pyx_v_tag_directive->prefix); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 574, __pyx_L1_error)
#20 13.16             |                                          ~~~~~~~~~~~~~~~~~~~~~^~~~~~~~
#20 13.16             |                                                               |
#20 13.16             |                                                               yaml_char_t * {aka unsigned char *}
#20 13.16       In file included from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/unicodeobject.h:138:17: note: expected ‘const char *’ but argument is of type ‘yaml_char_t *’ {aka ‘unsigned char *’}
#20 13.16         138 |     const char *u              /* UTF-8 encoded string */
#20 13.16             |     ~~~~~~~~~~~~^
#20 13.16       ext/_ruamel_yaml.c:8715:63: warning: pointer targets in passing argument 1 of ‘PyUnicode_FromString’ differ in signedness [-Wpointer-sign]
#20 13.16        8715 |     __pyx_t_4 = PyUnicode_FromString(__pyx_v_event->data.alias.anchor); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 585, __pyx_L1_error)
#20 13.16             |                                      ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
#20 13.16             |                                                               |
#20 13.16             |                                                               yaml_char_t * {aka unsigned char *}
#20 13.16       In file included from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/unicodeobject.h:138:17: note: expected ‘const char *’ but argument is of type ‘yaml_char_t *’ {aka ‘unsigned char *’}
#20 13.16         138 |     const char *u              /* UTF-8 encoded string */
#20 13.16             |     ~~~~~~~~~~~~^
#20 13.16       ext/_ruamel_yaml.c:8819:66: warning: pointer targets in passing argument 1 of ‘PyUnicode_FromString’ differ in signedness [-Wpointer-sign]
#20 13.16        8819 |       __pyx_t_4 = PyUnicode_FromString(__pyx_v_event->data.scalar.anchor); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 590, __pyx_L1_error)
#20 13.16             |                                        ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
#20 13.16             |                                                                  |
#20 13.16             |                                                                  yaml_char_t * {aka unsigned char *}
#20 13.16       In file included from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/unicodeobject.h:138:17: note: expected ‘const char *’ but argument is of type ‘yaml_char_t *’ {aka ‘unsigned char *’}
#20 13.16         138 |     const char *u              /* UTF-8 encoded string */
#20 13.16             |     ~~~~~~~~~~~~^
#20 13.16       ext/_ruamel_yaml.c:8860:66: warning: pointer targets in passing argument 1 of ‘PyUnicode_FromString’ differ in signedness [-Wpointer-sign]
#20 13.16        8860 |       __pyx_t_4 = PyUnicode_FromString(__pyx_v_event->data.scalar.tag); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 593, __pyx_L1_error)
#20 13.16             |                                        ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
#20 13.16             |                                                                  |
#20 13.16             |                                                                  yaml_char_t * {aka unsigned char *}
#20 13.16       In file included from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/unicodeobject.h:138:17: note: expected ‘const char *’ but argument is of type ‘yaml_char_t *’ {aka ‘unsigned char *’}
#20 13.16         138 |     const char *u              /* UTF-8 encoded string */
#20 13.16             |     ~~~~~~~~~~~~^
#20 13.16       ext/_ruamel_yaml.c:8881:64: warning: pointer targets in passing argument 1 of ‘PyUnicode_DecodeUTF8’ differ in signedness [-Wpointer-sign]
#20 13.16        8881 |     __pyx_t_4 = PyUnicode_DecodeUTF8(__pyx_v_event->data.scalar.value, __pyx_v_event->data.scalar.length, ((char *)"strict")); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 594, __pyx_L1_error)
#20 13.16             |                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~
#20 13.16             |                                                                |
#20 13.16             |                                                                yaml_char_t * {aka unsigned char *}
#20 13.16       In file included from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/unicodeobject.h:455:17: note: expected ‘const char *’ but argument is of type ‘yaml_char_t *’ {aka ‘unsigned char *’}
#20 13.16         455 |     const char *string,         /* UTF-8 encoded string */
#20 13.16             |     ~~~~~~~~~~~~^~~~~~
#20 13.16       ext/_ruamel_yaml.c:9222:74: warning: pointer targets in passing argument 1 of ‘PyUnicode_FromString’ differ in signedness [-Wpointer-sign]
#20 13.16        9222 |       __pyx_t_4 = PyUnicode_FromString(__pyx_v_event->data.sequence_start.anchor); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 619, __pyx_L1_error)
#20 13.16             |                                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
#20 13.16             |                                                                          |
#20 13.16             |                                                                          yaml_char_t * {aka unsigned char *}
#20 13.16       In file included from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/unicodeobject.h:138:17: note: expected ‘const char *’ but argument is of type ‘yaml_char_t *’ {aka ‘unsigned char *’}
#20 13.16         138 |     const char *u              /* UTF-8 encoded string */
#20 13.16             |     ~~~~~~~~~~~~^
#20 13.16       ext/_ruamel_yaml.c:9263:74: warning: pointer targets in passing argument 1 of ‘PyUnicode_FromString’ differ in signedness [-Wpointer-sign]
#20 13.16        9263 |       __pyx_t_4 = PyUnicode_FromString(__pyx_v_event->data.sequence_start.tag); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 622, __pyx_L1_error)
#20 13.16             |                                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
#20 13.16             |                                                                          |
#20 13.16             |                                                                          yaml_char_t * {aka unsigned char *}
#20 13.16       In file included from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/unicodeobject.h:138:17: note: expected ‘const char *’ but argument is of type ‘yaml_char_t *’ {aka ‘unsigned char *’}
#20 13.16         138 |     const char *u              /* UTF-8 encoded string */
#20 13.16             |     ~~~~~~~~~~~~^
#20 13.16       ext/_ruamel_yaml.c:9495:73: warning: pointer targets in passing argument 1 of ‘PyUnicode_FromString’ differ in signedness [-Wpointer-sign]
#20 13.16        9495 |       __pyx_t_4 = PyUnicode_FromString(__pyx_v_event->data.mapping_start.anchor); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 636, __pyx_L1_error)
#20 13.16             |                                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
#20 13.16             |                                                                         |
#20 13.16             |                                                                         yaml_char_t * {aka unsigned char *}
#20 13.16       In file included from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/unicodeobject.h:138:17: note: expected ‘const char *’ but argument is of type ‘yaml_char_t *’ {aka ‘unsigned char *’}
#20 13.16         138 |     const char *u              /* UTF-8 encoded string */
#20 13.16             |     ~~~~~~~~~~~~^
#20 13.16       ext/_ruamel_yaml.c:9536:73: warning: pointer targets in passing argument 1 of ‘PyUnicode_FromString’ differ in signedness [-Wpointer-sign]
#20 13.16        9536 |       __pyx_t_4 = PyUnicode_FromString(__pyx_v_event->data.mapping_start.tag); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 639, __pyx_L1_error)
#20 13.16             |                                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
#20 13.16             |                                                                         |
#20 13.16             |                                                                         yaml_char_t * {aka unsigned char *}
#20 13.16       In file included from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/unicodeobject.h:138:17: note: expected ‘const char *’ but argument is of type ‘yaml_char_t *’ {aka ‘unsigned char *’}
#20 13.16         138 |     const char *u              /* UTF-8 encoded string */
#20 13.16             |     ~~~~~~~~~~~~^
#20 13.16       ext/_ruamel_yaml.c: In function ‘__pyx_f_12_ruamel_yaml_7CParser__compose_node’:
#20 13.16       ext/_ruamel_yaml.c:11209:75: warning: pointer targets in passing argument 1 of ‘PyUnicode_FromString’ differ in signedness [-Wpointer-sign]
#20 13.16       11209 |     __pyx_t_3 = PyUnicode_FromString(__pyx_v_self->parsed_event.data.alias.anchor); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 733, __pyx_L1_error)
#20 13.16             |                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
#20 13.16             |                                                                           |
#20 13.16             |                                                                           yaml_char_t * {aka unsigned char *}
#20 13.16       In file included from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/unicodeobject.h:138:17: note: expected ‘const char *’ but argument is of type ‘yaml_char_t *’ {aka ‘unsigned char *’}
#20 13.16         138 |     const char *u              /* UTF-8 encoded string */
#20 13.16             |     ~~~~~~~~~~~~^
#20 13.16       ext/_ruamel_yaml.c:11529:76: warning: pointer targets in passing argument 1 of ‘PyUnicode_FromString’ differ in signedness [-Wpointer-sign]
#20 13.16       11529 |     __pyx_t_6 = PyUnicode_FromString(__pyx_v_self->parsed_event.data.scalar.anchor); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 749, __pyx_L1_error)
#20 13.16             |                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
#20 13.16             |                                                                            |
#20 13.16             |                                                                            yaml_char_t * {aka unsigned char *}
#20 13.16       In file included from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/unicodeobject.h:138:17: note: expected ‘const char *’ but argument is of type ‘yaml_char_t *’ {aka ‘unsigned char *’}
#20 13.16         138 |     const char *u              /* UTF-8 encoded string */
#20 13.16             |     ~~~~~~~~~~~~^
#20 13.16       ext/_ruamel_yaml.c:11585:84: warning: pointer targets in passing argument 1 of ‘PyUnicode_FromString’ differ in signedness [-Wpointer-sign]
#20 13.16       11585 |     __pyx_t_6 = PyUnicode_FromString(__pyx_v_self->parsed_event.data.sequence_start.anchor); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 752, __pyx_L1_error)
#20 13.16             |                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
#20 13.16             |                                                                                    |
#20 13.16             |                                                                                    yaml_char_t * {aka unsigned char *}
#20 13.16       In file included from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/unicodeobject.h:138:17: note: expected ‘const char *’ but argument is of type ‘yaml_char_t *’ {aka ‘unsigned char *’}
#20 13.16         138 |     const char *u              /* UTF-8 encoded string */
#20 13.16             |     ~~~~~~~~~~~~^
#20 13.16       ext/_ruamel_yaml.c:11641:83: warning: pointer targets in passing argument 1 of ‘PyUnicode_FromString’ differ in signedness [-Wpointer-sign]
#20 13.16       11641 |     __pyx_t_6 = PyUnicode_FromString(__pyx_v_self->parsed_event.data.mapping_start.anchor); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 755, __pyx_L1_error)
#20 13.16             |                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
#20 13.16             |                                                                                   |
#20 13.16             |                                                                                   yaml_char_t * {aka unsigned char *}
#20 13.16       In file included from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/unicodeobject.h:138:17: note: expected ‘const char *’ but argument is of type ‘yaml_char_t *’ {aka ‘unsigned char *’}
#20 13.16         138 |     const char *u              /* UTF-8 encoded string */
#20 13.16             |     ~~~~~~~~~~~~^
#20 13.16       ext/_ruamel_yaml.c: In function ‘__pyx_f_12_ruamel_yaml_7CParser__compose_scalar_node’:
#20 13.16       ext/_ruamel_yaml.c:12299:74: warning: pointer targets in passing argument 1 of ‘PyUnicode_DecodeUTF8’ differ in signedness [-Wpointer-sign]
#20 13.16       12299 |   __pyx_t_2 = PyUnicode_DecodeUTF8(__pyx_v_self->parsed_event.data.scalar.value, __pyx_v_self->parsed_event.data.scalar.length, ((char *)"strict")); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 790, __pyx_L1_error)
#20 13.16             |                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~
#20 13.16             |                                                                          |
#20 13.16             |                                                                          yaml_char_t * {aka unsigned char *}
#20 13.16       In file included from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/unicodeobject.h:455:17: note: expected ‘const char *’ but argument is of type ‘yaml_char_t *’ {aka ‘unsigned char *’}
#20 13.16         455 |     const char *string,         /* UTF-8 encoded string */
#20 13.16             |     ~~~~~~~~~~~~^~~~~~
#20 13.16       ext/_ruamel_yaml.c:12522:76: warning: pointer targets in passing argument 1 of ‘PyUnicode_FromString’ differ in signedness [-Wpointer-sign]
#20 13.16       12522 |     __pyx_t_2 = PyUnicode_FromString(__pyx_v_self->parsed_event.data.scalar.tag); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 803, __pyx_L1_error)
#20 13.16             |                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
#20 13.16             |                                                                            |
#20 13.16             |                                                                            yaml_char_t * {aka unsigned char *}
#20 13.16       In file included from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/unicodeobject.h:138:17: note: expected ‘const char *’ but argument is of type ‘yaml_char_t *’ {aka ‘unsigned char *’}
#20 13.16         138 |     const char *u              /* UTF-8 encoded string */
#20 13.16             |     ~~~~~~~~~~~~^
#20 13.16       ext/_ruamel_yaml.c: In function ‘__pyx_f_12_ruamel_yaml_7CParser__compose_sequence_node’:
#20 13.16       ext/_ruamel_yaml.c:13060:84: warning: pointer targets in passing argument 1 of ‘PyUnicode_FromString’ differ in signedness [-Wpointer-sign]
#20 13.16       13060 |     __pyx_t_3 = PyUnicode_FromString(__pyx_v_self->parsed_event.data.sequence_start.tag); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 836, __pyx_L1_error)
#20 13.16             |                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
#20 13.16             |                                                                                    |
#20 13.16             |                                                                                    yaml_char_t * {aka unsigned char *}
#20 13.16       In file included from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/unicodeobject.h:138:17: note: expected ‘const char *’ but argument is of type ‘yaml_char_t *’ {aka ‘unsigned char *’}
#20 13.16         138 |     const char *u              /* UTF-8 encoded string */
#20 13.16             |     ~~~~~~~~~~~~^
#20 13.16       ext/_ruamel_yaml.c: In function ‘__pyx_f_12_ruamel_yaml_7CParser__compose_mapping_node’:
#20 13.16       ext/_ruamel_yaml.c:13685:83: warning: pointer targets in passing argument 1 of ‘PyUnicode_FromString’ differ in signedness [-Wpointer-sign]
#20 13.16       13685 |     __pyx_t_3 = PyUnicode_FromString(__pyx_v_self->parsed_event.data.mapping_start.tag); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 875, __pyx_L1_error)
#20 13.16             |                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
#20 13.16             |                                                                                   |
#20 13.16             |                                                                                   yaml_char_t * {aka unsigned char *}
#20 13.16       In file included from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/unicodeobject.h:138:17: note: expected ‘const char *’ but argument is of type ‘yaml_char_t *’ {aka ‘unsigned char *’}
#20 13.16         138 |     const char *u              /* UTF-8 encoded string */
#20 13.16             |     ~~~~~~~~~~~~^
#20 13.16       ext/_ruamel_yaml.c: In function ‘__pyx_pf_12_ruamel_yaml_8CEmitter___init__’:
#20 13.16       ext/_ruamel_yaml.c:15016:53: warning: passing argument 2 of ‘yaml_emitter_set_output’ from incompatible pointer type [-Wincompatible-pointer-types]
#20 13.16       15016 |   yaml_emitter_set_output((&__pyx_v_self->emitter), __pyx_f_12_ruamel_yaml_output_handler, ((void *)__pyx_v_self));
#20 13.16             |                                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#20 13.16             |                                                     |
#20 13.16             |                                                     int (*)(void *, char *, int)
#20 13.16       In file included from ext/_ruamel_yaml.h:2,
#20 13.16                        from ext/_ruamel_yaml.c:596:
#20 13.16       ext/yaml.h:1837:31: note: expected ‘int (*)(void *, unsigned char *, size_t)’ {aka ‘int (*)(void *, unsigned char *, long unsigned int)’} but argument is of type ‘int (*)(void *, char *, int)’
#20 13.16        1837 |         yaml_write_handler_t *handler, void *data);
#20 13.16             |         ~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
#20 13.16       ext/_ruamel_yaml.c: In function ‘__pyx_f_12_ruamel_yaml_8CEmitter__object_to_event’:
#20 13.16       ext/_ruamel_yaml.c:16368:44: warning: pointer targets in assignment from ‘char *’ to ‘yaml_char_t *’ {aka ‘unsigned char *’} differ in signedness [-Wpointer-sign]
#20 13.16       16368 |         __pyx_v_tag_directives_end->handle = PyString_AS_STRING(__pyx_v_handle);
#20 13.16             |                                            ^
#20 13.16       ext/_ruamel_yaml.c:16483:44: warning: pointer targets in assignment from ‘char *’ to ‘yaml_char_t *’ {aka ‘unsigned char *’} differ in signedness [-Wpointer-sign]
#20 13.16       16483 |         __pyx_v_tag_directives_end->prefix = PyString_AS_STRING(__pyx_v_prefix);
#20 13.16             |                                            ^
#20 13.16       ext/_ruamel_yaml.c:16820:62: warning: pointer targets in passing argument 2 of ‘yaml_alias_event_initialize’ differ in signedness [-Wpointer-sign]
#20 13.16       16820 |     __pyx_t_2 = ((yaml_alias_event_initialize(__pyx_v_event, __pyx_v_anchor) == 0) != 0);
#20 13.16             |                                                              ^~~~~~~~~~~~~~
#20 13.16             |                                                              |
#20 13.16             |                                                              char *
#20 13.16       In file included from ext/_ruamel_yaml.h:2,
#20 13.16                        from ext/_ruamel_yaml.c:596:
#20 13.16       ext/yaml.h:555:63: note: expected ‘yaml_char_t *’ {aka ‘unsigned char *’} but argument is of type ‘char *’
#20 13.16         555 | yaml_alias_event_initialize(yaml_event_t *event, yaml_char_t *anchor);
#20 13.16             |                                                  ~~~~~~~~~~~~~^~~~~~
#20 13.16       ext/_ruamel_yaml.c:17535:63: warning: pointer targets in passing argument 2 of ‘yaml_scalar_event_initialize’ differ in signedness [-Wpointer-sign]
#20 13.16       17535 |     __pyx_t_2 = ((yaml_scalar_event_initialize(__pyx_v_event, __pyx_v_anchor, __pyx_v_tag, __pyx_v_value, __pyx_v_length, __pyx_v_plain_implicit, __pyx_v_quoted_implicit, __pyx_v_scalar_style) == 0) != 0);
#20 13.16             |                                                               ^~~~~~~~~~~~~~
#20 13.16             |                                                               |
#20 13.16             |                                                               char *
#20 13.16       In file included from ext/_ruamel_yaml.h:2,
#20 13.16                        from ext/_ruamel_yaml.c:596:
#20 13.16       ext/yaml.h:581:22: note: expected ‘yaml_char_t *’ {aka ‘unsigned char *’} but argument is of type ‘char *’
#20 13.16         581 |         yaml_char_t *anchor, yaml_char_t *tag,
#20 13.16             |         ~~~~~~~~~~~~~^~~~~~
#20 13.16       ext/_ruamel_yaml.c:17535:79: warning: pointer targets in passing argument 3 of ‘yaml_scalar_event_initialize’ differ in signedness [-Wpointer-sign]
#20 13.16       17535 |     __pyx_t_2 = ((yaml_scalar_event_initialize(__pyx_v_event, __pyx_v_anchor, __pyx_v_tag, __pyx_v_value, __pyx_v_length, __pyx_v_plain_implicit, __pyx_v_quoted_implicit, __pyx_v_scalar_style) == 0) != 0);
#20 13.16             |                                                                               ^~~~~~~~~~~
#20 13.16             |                                                                               |
#20 13.16             |                                                                               char *
#20 13.16       In file included from ext/_ruamel_yaml.h:2,
#20 13.16                        from ext/_ruamel_yaml.c:596:
#20 13.16       ext/yaml.h:581:43: note: expected ‘yaml_char_t *’ {aka ‘unsigned char *’} but argument is of type ‘char *’
#20 13.16         581 |         yaml_char_t *anchor, yaml_char_t *tag,
#20 13.16             |                              ~~~~~~~~~~~~~^~~
#20 13.16       ext/_ruamel_yaml.c:17535:92: warning: pointer targets in passing argument 4 of ‘yaml_scalar_event_initialize’ differ in signedness [-Wpointer-sign]
#20 13.16       17535 |     __pyx_t_2 = ((yaml_scalar_event_initialize(__pyx_v_event, __pyx_v_anchor, __pyx_v_tag, __pyx_v_value, __pyx_v_length, __pyx_v_plain_implicit, __pyx_v_quoted_implicit, __pyx_v_scalar_style) == 0) != 0);
#20 13.16             |                                                                                            ^~~~~~~~~~~~~
#20 13.16             |                                                                                            |
#20 13.16             |                                                                                            char *
#20 13.16       In file included from ext/_ruamel_yaml.h:2,
#20 13.16                        from ext/_ruamel_yaml.c:596:
#20 13.16       ext/yaml.h:582:22: note: expected ‘yaml_char_t *’ {aka ‘unsigned char *’} but argument is of type ‘char *’
#20 13.16         582 |         yaml_char_t *value, int length,
#20 13.16             |         ~~~~~~~~~~~~~^~~~~
#20 13.16       ext/_ruamel_yaml.c:17969:71: warning: pointer targets in passing argument 2 of ‘yaml_sequence_start_event_initialize’ differ in signedness [-Wpointer-sign]
#20 13.16       17969 |     __pyx_t_3 = ((yaml_sequence_start_event_initialize(__pyx_v_event, __pyx_v_anchor, __pyx_v_tag, __pyx_v_implicit, __pyx_v_sequence_style) == 0) != 0);
#20 13.16             |                                                                       ^~~~~~~~~~~~~~
#20 13.16             |                                                                       |
#20 13.16             |                                                                       char *
#20 13.16       In file included from ext/_ruamel_yaml.h:2,
#20 13.16                        from ext/_ruamel_yaml.c:596:
#20 13.16       ext/yaml.h:604:22: note: expected ‘yaml_char_t *’ {aka ‘unsigned char *’} but argument is of type ‘char *’
#20 13.16         604 |         yaml_char_t *anchor, yaml_char_t *tag, int implicit,
#20 13.16             |         ~~~~~~~~~~~~~^~~~~~
#20 13.16       ext/_ruamel_yaml.c:17969:87: warning: pointer targets in passing argument 3 of ‘yaml_sequence_start_event_initialize’ differ in signedness [-Wpointer-sign]
#20 13.16       17969 |     __pyx_t_3 = ((yaml_sequence_start_event_initialize(__pyx_v_event, __pyx_v_anchor, __pyx_v_tag, __pyx_v_implicit, __pyx_v_sequence_style) == 0) != 0);
#20 13.16             |                                                                                       ^~~~~~~~~~~
#20 13.16             |                                                                                       |
#20 13.16             |                                                                                       char *
#20 13.16       In file included from ext/_ruamel_yaml.h:2,
#20 13.16                        from ext/_ruamel_yaml.c:596:
#20 13.16       ext/yaml.h:604:43: note: expected ‘yaml_char_t *’ {aka ‘unsigned char *’} but argument is of type ‘char *’
#20 13.16         604 |         yaml_char_t *anchor, yaml_char_t *tag, int implicit,
#20 13.16             |                              ~~~~~~~~~~~~~^~~
#20 13.16       ext/_ruamel_yaml.c:18403:70: warning: pointer targets in passing argument 2 of ‘yaml_mapping_start_event_initialize’ differ in signedness [-Wpointer-sign]
#20 13.16       18403 |     __pyx_t_2 = ((yaml_mapping_start_event_initialize(__pyx_v_event, __pyx_v_anchor, __pyx_v_tag, __pyx_v_implicit, __pyx_v_mapping_style) == 0) != 0);
#20 13.16             |                                                                      ^~~~~~~~~~~~~~
#20 13.16             |                                                                      |
#20 13.16             |                                                                      char *
#20 13.16       In file included from ext/_ruamel_yaml.h:2,
#20 13.16                        from ext/_ruamel_yaml.c:596:
#20 13.16       ext/yaml.h:636:22: note: expected ‘yaml_char_t *’ {aka ‘unsigned char *’} but argument is of type ‘char *’
#20 13.16         636 |         yaml_char_t *anchor, yaml_char_t *tag, int implicit,
#20 13.16             |         ~~~~~~~~~~~~~^~~~~~
#20 13.16       ext/_ruamel_yaml.c:18403:86: warning: pointer targets in passing argument 3 of ‘yaml_mapping_start_event_initialize’ differ in signedness [-Wpointer-sign]
#20 13.16       18403 |     __pyx_t_2 = ((yaml_mapping_start_event_initialize(__pyx_v_event, __pyx_v_anchor, __pyx_v_tag, __pyx_v_implicit, __pyx_v_mapping_style) == 0) != 0);
#20 13.16             |                                                                                      ^~~~~~~~~~~
#20 13.16             |                                                                                      |
#20 13.16             |                                                                                      char *
#20 13.16       In file included from ext/_ruamel_yaml.h:2,
#20 13.16                        from ext/_ruamel_yaml.c:596:
#20 13.16       ext/yaml.h:636:43: note: expected ‘yaml_char_t *’ {aka ‘unsigned char *’} but argument is of type ‘char *’
#20 13.16         636 |         yaml_char_t *anchor, yaml_char_t *tag, int implicit,
#20 13.16             |                              ~~~~~~~~~~~~~^~~
#20 13.16       ext/_ruamel_yaml.c: In function ‘__pyx_pf_12_ruamel_yaml_8CEmitter_12serialize’:
#20 13.16       ext/_ruamel_yaml.c:19973:42: warning: pointer targets in assignment from ‘char *’ to ‘yaml_char_t *’ {aka ‘unsigned char *’} differ in signedness [-Wpointer-sign]
#20 13.16       19973 |       __pyx_v_tag_directives_end->handle = PyString_AS_STRING(__pyx_v_handle);
#20 13.16             |                                          ^
#20 13.16       ext/_ruamel_yaml.c:20088:42: warning: pointer targets in assignment from ‘char *’ to ‘yaml_char_t *’ {aka ‘unsigned char *’} differ in signedness [-Wpointer-sign]
#20 13.16       20088 |       __pyx_v_tag_directives_end->prefix = PyString_AS_STRING(__pyx_v_prefix);
#20 13.16             |                                          ^
#20 13.16       ext/_ruamel_yaml.c: In function ‘__pyx_f_12_ruamel_yaml_8CEmitter__serialize_node’:
#20 13.16       ext/_ruamel_yaml.c:20945:65: warning: pointer targets in passing argument 2 of ‘yaml_alias_event_initialize’ differ in signedness [-Wpointer-sign]
#20 13.16       20945 |     __pyx_t_2 = ((yaml_alias_event_initialize((&__pyx_v_event), __pyx_v_anchor) == 0) != 0);
#20 13.16             |                                                                 ^~~~~~~~~~~~~~
#20 13.16             |                                                                 |
#20 13.16             |                                                                 char *
#20 13.16       In file included from ext/_ruamel_yaml.h:2,
#20 13.16                        from ext/_ruamel_yaml.c:596:
#20 13.16       ext/yaml.h:555:63: note: expected ‘yaml_char_t *’ {aka ‘unsigned char *’} but argument is of type ‘char *’
#20 13.16         555 | yaml_alias_event_initialize(yaml_event_t *event, yaml_char_t *anchor);
#20 13.16             |                                                  ~~~~~~~~~~~~~^~~~~~
#20 13.16       ext/_ruamel_yaml.c:21756:68: warning: pointer targets in passing argument 2 of ‘yaml_scalar_event_initialize’ differ in signedness [-Wpointer-sign]
#20 13.16       21756 |       __pyx_t_2 = ((yaml_scalar_event_initialize((&__pyx_v_event), __pyx_v_anchor, __pyx_v_tag, __pyx_v_value, __pyx_v_length, __pyx_v_plain_implicit, __pyx_v_quoted_implicit, __pyx_v_scalar_style) == 0) != 0);
#20 13.16             |                                                                    ^~~~~~~~~~~~~~
#20 13.16             |                                                                    |
#20 13.16             |                                                                    char *
#20 13.16       In file included from ext/_ruamel_yaml.h:2,
#20 13.16                        from ext/_ruamel_yaml.c:596:
#20 13.16       ext/yaml.h:581:22: note: expected ‘yaml_char_t *’ {aka ‘unsigned char *’} but argument is of type ‘char *’
#20 13.16         581 |         yaml_char_t *anchor, yaml_char_t *tag,
#20 13.16             |         ~~~~~~~~~~~~~^~~~~~
#20 13.16       ext/_ruamel_yaml.c:21756:84: warning: pointer targets in passing argument 3 of ‘yaml_scalar_event_initialize’ differ in signedness [-Wpointer-sign]
#20 13.16       21756 |       __pyx_t_2 = ((yaml_scalar_event_initialize((&__pyx_v_event), __pyx_v_anchor, __pyx_v_tag, __pyx_v_value, __pyx_v_length, __pyx_v_plain_implicit, __pyx_v_quoted_implicit, __pyx_v_scalar_style) == 0) != 0);
#20 13.16             |                                                                                    ^~~~~~~~~~~
#20 13.16             |                                                                                    |
#20 13.16             |                                                                                    char *
#20 13.16       In file included from ext/_ruamel_yaml.h:2,
#20 13.16                        from ext/_ruamel_yaml.c:596:
#20 13.16       ext/yaml.h:581:43: note: expected ‘yaml_char_t *’ {aka ‘unsigned char *’} but argument is of type ‘char *’
#20 13.16         581 |         yaml_char_t *anchor, yaml_char_t *tag,
#20 13.16             |                              ~~~~~~~~~~~~~^~~
#20 13.16       ext/_ruamel_yaml.c:21756:97: warning: pointer targets in passing argument 4 of ‘yaml_scalar_event_initialize’ differ in signedness [-Wpointer-sign]
#20 13.16       21756 |       __pyx_t_2 = ((yaml_scalar_event_initialize((&__pyx_v_event), __pyx_v_anchor, __pyx_v_tag, __pyx_v_value, __pyx_v_length, __pyx_v_plain_implicit, __pyx_v_quoted_implicit, __pyx_v_scalar_style) == 0) != 0);
#20 13.16             |                                                                                                 ^~~~~~~~~~~~~
#20 13.16             |                                                                                                 |
#20 13.16             |                                                                                                 char *
#20 13.16       In file included from ext/_ruamel_yaml.h:2,
#20 13.16                        from ext/_ruamel_yaml.c:596:
#20 13.16       ext/yaml.h:582:22: note: expected ‘yaml_char_t *’ {aka ‘unsigned char *’} but argument is of type ‘char *’
#20 13.16         582 |         yaml_char_t *value, int length,
#20 13.16             |         ~~~~~~~~~~~~~^~~~~
#20 13.16       ext/_ruamel_yaml.c:22143:76: warning: pointer targets in passing argument 2 of ‘yaml_sequence_start_event_initialize’ differ in signedness [-Wpointer-sign]
#20 13.16       22143 |       __pyx_t_2 = ((yaml_sequence_start_event_initialize((&__pyx_v_event), __pyx_v_anchor, __pyx_v_tag, __pyx_v_implicit, __pyx_v_sequence_style) == 0) != 0);
#20 13.16             |                                                                            ^~~~~~~~~~~~~~
#20 13.16             |                                                                            |
#20 13.16             |                                                                            char *
#20 13.16       In file included from ext/_ruamel_yaml.h:2,
#20 13.16                        from ext/_ruamel_yaml.c:596:
#20 13.16       ext/yaml.h:604:22: note: expected ‘yaml_char_t *’ {aka ‘unsigned char *’} but argument is of type ‘char *’
#20 13.16         604 |         yaml_char_t *anchor, yaml_char_t *tag, int implicit,
#20 13.16             |         ~~~~~~~~~~~~~^~~~~~
#20 13.16       ext/_ruamel_yaml.c:22143:92: warning: pointer targets in passing argument 3 of ‘yaml_sequence_start_event_initialize’ differ in signedness [-Wpointer-sign]
#20 13.16       22143 |       __pyx_t_2 = ((yaml_sequence_start_event_initialize((&__pyx_v_event), __pyx_v_anchor, __pyx_v_tag, __pyx_v_implicit, __pyx_v_sequence_style) == 0) != 0);
#20 13.16             |                                                                                            ^~~~~~~~~~~
#20 13.16             |                                                                                            |
#20 13.16             |                                                                                            char *
#20 13.16       In file included from ext/_ruamel_yaml.h:2,
#20 13.16                        from ext/_ruamel_yaml.c:596:
#20 13.16       ext/yaml.h:604:43: note: expected ‘yaml_char_t *’ {aka ‘unsigned char *’} but argument is of type ‘char *’
#20 13.16         604 |         yaml_char_t *anchor, yaml_char_t *tag, int implicit,
#20 13.16             |                              ~~~~~~~~~~~~~^~~
#20 13.16       ext/_ruamel_yaml.c:22673:75: warning: pointer targets in passing argument 2 of ‘yaml_mapping_start_event_initialize’ differ in signedness [-Wpointer-sign]
#20 13.16       22673 |       __pyx_t_2 = ((yaml_mapping_start_event_initialize((&__pyx_v_event), __pyx_v_anchor, __pyx_v_tag, __pyx_v_implicit, __pyx_v_mapping_style) == 0) != 0);
#20 13.16             |                                                                           ^~~~~~~~~~~~~~
#20 13.16             |                                                                           |
#20 13.16             |                                                                           char *
#20 13.16       In file included from ext/_ruamel_yaml.h:2,
#20 13.16                        from ext/_ruamel_yaml.c:596:
#20 13.16       ext/yaml.h:636:22: note: expected ‘yaml_char_t *’ {aka ‘unsigned char *’} but argument is of type ‘char *’
#20 13.16         636 |         yaml_char_t *anchor, yaml_char_t *tag, int implicit,
#20 13.16             |         ~~~~~~~~~~~~~^~~~~~
#20 13.16       ext/_ruamel_yaml.c:22673:91: warning: pointer targets in passing argument 3 of ‘yaml_mapping_start_event_initialize’ differ in signedness [-Wpointer-sign]
#20 13.16       22673 |       __pyx_t_2 = ((yaml_mapping_start_event_initialize((&__pyx_v_event), __pyx_v_anchor, __pyx_v_tag, __pyx_v_implicit, __pyx_v_mapping_style) == 0) != 0);
#20 13.16             |                                                                                           ^~~~~~~~~~~
#20 13.16             |                                                                                           |
#20 13.16             |                                                                                           char *
#20 13.16       In file included from ext/_ruamel_yaml.h:2,
#20 13.16                        from ext/_ruamel_yaml.c:596:
#20 13.16       ext/yaml.h:636:43: note: expected ‘yaml_char_t *’ {aka ‘unsigned char *’} but argument is of type ‘char *’
#20 13.16         636 |         yaml_char_t *anchor, yaml_char_t *tag, int implicit,
#20 13.16             |                              ~~~~~~~~~~~~~^~~
#20 13.16       ext/_ruamel_yaml.c: In function ‘__pyx_tp_dealloc_12_ruamel_yaml_CParser’:
#20 13.16       ext/_ruamel_yaml.c:23877:5: error: lvalue required as increment operand
#20 13.16       23877 |     ++Py_REFCNT(o);
#20 13.16             |     ^~
#20 13.16       ext/_ruamel_yaml.c:23879:5: error: lvalue required as decrement operand
#20 13.16       23879 |     --Py_REFCNT(o);
#20 13.16             |     ^~
#20 13.16       ext/_ruamel_yaml.c: In function ‘__pyx_tp_dealloc_12_ruamel_yaml_CEmitter’:
#20 13.16       ext/_ruamel_yaml.c:24050:5: error: lvalue required as increment operand
#20 13.16       24050 |     ++Py_REFCNT(o);
#20 13.16             |     ^~
#20 13.16       ext/_ruamel_yaml.c:24052:5: error: lvalue required as decrement operand
#20 13.16       24052 |     --Py_REFCNT(o);
#20 13.16             |     ^~
#20 13.16       ext/_ruamel_yaml.c: In function ‘__Pyx_ParseOptionalKeywords’:
#20 13.16       ext/_ruamel_yaml.c:26221:21: warning: ‘_PyUnicode_get_wstr_length’ is deprecated [-Wdeprecated-declarations]
#20 13.16       26221 |                     (PyUnicode_GET_SIZE(**name) != PyUnicode_GET_SIZE(key)) ? 1 :
#20 13.16             |                     ^
#20 13.16       In file included from /usr/local/include/python3.10/unicodeobject.h:1046,
#20 13.16                        from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/cpython/unicodeobject.h:446:26: note: declared here
#20 13.16         446 | static inline Py_ssize_t _PyUnicode_get_wstr_length(PyObject *op) {
#20 13.16             |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~
#20 13.16       ext/_ruamel_yaml.c:26221:21: warning: ‘PyUnicode_AsUnicode’ is deprecated [-Wdeprecated-declarations]
#20 13.16       26221 |                     (PyUnicode_GET_SIZE(**name) != PyUnicode_GET_SIZE(key)) ? 1 :
#20 13.16             |                     ^
#20 13.16       In file included from /usr/local/include/python3.10/unicodeobject.h:1046,
#20 13.16                        from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/cpython/unicodeobject.h:580:45: note: declared here
#20 13.16         580 | Py_DEPRECATED(3.3) PyAPI_FUNC(Py_UNICODE *) PyUnicode_AsUnicode(
#20 13.16             |                                             ^~~~~~~~~~~~~~~~~~~
#20 13.16       ext/_ruamel_yaml.c:26221:21: warning: ‘_PyUnicode_get_wstr_length’ is deprecated [-Wdeprecated-declarations]
#20 13.16       26221 |                     (PyUnicode_GET_SIZE(**name) != PyUnicode_GET_SIZE(key)) ? 1 :
#20 13.16             |                     ^
#20 13.16       In file included from /usr/local/include/python3.10/unicodeobject.h:1046,
#20 13.16                        from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/cpython/unicodeobject.h:446:26: note: declared here
#20 13.16         446 | static inline Py_ssize_t _PyUnicode_get_wstr_length(PyObject *op) {
#20 13.16             |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~
#20 13.16       ext/_ruamel_yaml.c:26221:21: warning: ‘_PyUnicode_get_wstr_length’ is deprecated [-Wdeprecated-declarations]
#20 13.16       26221 |                     (PyUnicode_GET_SIZE(**name) != PyUnicode_GET_SIZE(key)) ? 1 :
#20 13.16             |                     ^
#20 13.16       In file included from /usr/local/include/python3.10/unicodeobject.h:1046,
#20 13.16                        from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/cpython/unicodeobject.h:446:26: note: declared here
#20 13.16         446 | static inline Py_ssize_t _PyUnicode_get_wstr_length(PyObject *op) {
#20 13.16             |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~
#20 13.16       ext/_ruamel_yaml.c:26221:21: warning: ‘PyUnicode_AsUnicode’ is deprecated [-Wdeprecated-declarations]
#20 13.16       26221 |                     (PyUnicode_GET_SIZE(**name) != PyUnicode_GET_SIZE(key)) ? 1 :
#20 13.16             |                     ^
#20 13.16       In file included from /usr/local/include/python3.10/unicodeobject.h:1046,
#20 13.16                        from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/cpython/unicodeobject.h:580:45: note: declared here
#20 13.16         580 | Py_DEPRECATED(3.3) PyAPI_FUNC(Py_UNICODE *) PyUnicode_AsUnicode(
#20 13.16             |                                             ^~~~~~~~~~~~~~~~~~~
#20 13.16       ext/_ruamel_yaml.c:26221:21: warning: ‘_PyUnicode_get_wstr_length’ is deprecated [-Wdeprecated-declarations]
#20 13.16       26221 |                     (PyUnicode_GET_SIZE(**name) != PyUnicode_GET_SIZE(key)) ? 1 :
#20 13.16             |                     ^
#20 13.16       In file included from /usr/local/include/python3.10/unicodeobject.h:1046,
#20 13.16                        from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/cpython/unicodeobject.h:446:26: note: declared here
#20 13.16         446 | static inline Py_ssize_t _PyUnicode_get_wstr_length(PyObject *op) {
#20 13.16             |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~
#20 13.16       ext/_ruamel_yaml.c:26237:25: warning: ‘_PyUnicode_get_wstr_length’ is deprecated [-Wdeprecated-declarations]
#20 13.16       26237 |                         (PyUnicode_GET_SIZE(**argname) != PyUnicode_GET_SIZE(key)) ? 1 :
#20 13.16             |                         ^
#20 13.16       In file included from /usr/local/include/python3.10/unicodeobject.h:1046,
#20 13.16                        from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/cpython/unicodeobject.h:446:26: note: declared here
#20 13.16         446 | static inline Py_ssize_t _PyUnicode_get_wstr_length(PyObject *op) {
#20 13.16             |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~
#20 13.16       ext/_ruamel_yaml.c:26237:25: warning: ‘PyUnicode_AsUnicode’ is deprecated [-Wdeprecated-declarations]
#20 13.16       26237 |                         (PyUnicode_GET_SIZE(**argname) != PyUnicode_GET_SIZE(key)) ? 1 :
#20 13.16             |                         ^
#20 13.16       In file included from /usr/local/include/python3.10/unicodeobject.h:1046,
#20 13.16                        from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/cpython/unicodeobject.h:580:45: note: declared here
#20 13.16         580 | Py_DEPRECATED(3.3) PyAPI_FUNC(Py_UNICODE *) PyUnicode_AsUnicode(
#20 13.16             |                                             ^~~~~~~~~~~~~~~~~~~
#20 13.16       ext/_ruamel_yaml.c:26237:25: warning: ‘_PyUnicode_get_wstr_length’ is deprecated [-Wdeprecated-declarations]
#20 13.16       26237 |                         (PyUnicode_GET_SIZE(**argname) != PyUnicode_GET_SIZE(key)) ? 1 :
#20 13.16             |                         ^
#20 13.16       In file included from /usr/local/include/python3.10/unicodeobject.h:1046,
#20 13.16                        from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/cpython/unicodeobject.h:446:26: note: declared here
#20 13.16         446 | static inline Py_ssize_t _PyUnicode_get_wstr_length(PyObject *op) {
#20 13.16             |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~
#20 13.16       ext/_ruamel_yaml.c:26237:25: warning: ‘_PyUnicode_get_wstr_length’ is deprecated [-Wdeprecated-declarations]
#20 13.16       26237 |                         (PyUnicode_GET_SIZE(**argname) != PyUnicode_GET_SIZE(key)) ? 1 :
#20 13.16             |                         ^
#20 13.16       In file included from /usr/local/include/python3.10/unicodeobject.h:1046,
#20 13.16                        from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/cpython/unicodeobject.h:446:26: note: declared here
#20 13.16         446 | static inline Py_ssize_t _PyUnicode_get_wstr_length(PyObject *op) {
#20 13.16             |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~
#20 13.16       ext/_ruamel_yaml.c:26237:25: warning: ‘PyUnicode_AsUnicode’ is deprecated [-Wdeprecated-declarations]
#20 13.16       26237 |                         (PyUnicode_GET_SIZE(**argname) != PyUnicode_GET_SIZE(key)) ? 1 :
#20 13.16             |                         ^
#20 13.16       In file included from /usr/local/include/python3.10/unicodeobject.h:1046,
#20 13.16                        from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/cpython/unicodeobject.h:580:45: note: declared here
#20 13.16         580 | Py_DEPRECATED(3.3) PyAPI_FUNC(Py_UNICODE *) PyUnicode_AsUnicode(
#20 13.16             |                                             ^~~~~~~~~~~~~~~~~~~
#20 13.16       ext/_ruamel_yaml.c:26237:25: warning: ‘_PyUnicode_get_wstr_length’ is deprecated [-Wdeprecated-declarations]
#20 13.16       26237 |                         (PyUnicode_GET_SIZE(**argname) != PyUnicode_GET_SIZE(key)) ? 1 :
#20 13.16             |                         ^
#20 13.16       In file included from /usr/local/include/python3.10/unicodeobject.h:1046,
#20 13.16                        from /usr/local/include/python3.10/Python.h:83,
#20 13.16                        from ext/_ruamel_yaml.c:4:
#20 13.16       /usr/local/include/python3.10/cpython/unicodeobject.h:446:26: note: declared here
#20 13.16         446 | static inline Py_ssize_t _PyUnicode_get_wstr_length(PyObject *op) {
#20 13.16             |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~
#20 13.16       error: command '/usr/bin/gcc' failed with exit code 1
#20 13.16       [end of output]
#20 13.16   
#20 13.16   note: This error originates from a subprocess, and is likely not a problem with pip.
#20 13.16   Running setup.py clean for ruamel.yaml
#20 13.16   ERROR: Failed building wheel for ruamel.yaml
#20 13.47   Building wheel for strictyaml (setup.py): started

Python 3.11 missing longintrepr.h

#15 19.16       running build_ext
#15 19.16       building 'yarl._quoting_c' extension
#15 19.16       creating build/temp.linux-x86_64-cpython-311
#15 19.16       creating build/temp.linux-x86_64-cpython-311/yarl
#15 19.16       x86_64-linux-gnu-gcc -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -fPIC -I/usr/include/python3.11 -c yarl/_quoting_c.c -o build/temp.linux-x86_64-cpython-311/yarl/_quoting_c.o
#15 19.16       yarl/_quoting_c.c:196:12: fatal error: longintrepr.h: No such file or directory
#15 19.16         196 |   #include "longintrepr.h"
#15 19.16             |            ^~~~~~~~~~~~~~~
#15 19.16       compilation terminated.
#15 19.16       error: command '/usr/bin/x86_64-linux-gnu-gcc' failed with exit code 1
#15 19.16       [end of output]
#15 19.16   
#15 19.16   note: This error originates from a subprocess, and is likely not a problem with pip.
#15 19.16   ERROR: Failed building wheel for yarl
#15 19.17 Successfully built coverage crontab MarkupSafe multidict strictyaml
#15 19.17 Failed to build aiohttp ruamel.yaml yarl
#15 19.17 ERROR: Could not build wheels for aiohttp, yarl, which is required to install pyproject.toml-based projects
#15 ERROR: process "/bin/sh -c pip install -r /root/requirements.txt" did not complete successfully: exit code: 1

As building with python 3.11 stop at library missing, still dont know if there will be another error poped out.

Thanks.

Install error on Ubuntu 16.04/Python 3.5

  • Yet Another Cron version: 0.10
  • Python version: 3.5
  • Operating System: Ubuntu 16.04

Description

Trying to install Yacron on Ubuntu 16.04

virtualenv -p /usr/bin/python3 /yacron &&  /yacron/bin/pip install yacron

results in error

ERROR: Could not find a version that satisfies the requirement aiohttp>=3.0 (from yacron) (from versions: 0.1, 0.2, 0.3, 0.4, 0.4.1, 0.4.2, 0.4.3, 0.4.4, 0.5.0, 0.6.0, 0.6.1, 0.6.2, 0.6.3, 0.6.4, 0.6.5, 0.7.0, 0.7.1, 0.7.2, 0.7.3, 0.8.0, 0.8.1, 0.8.2, 0.8.3, 0.8.4, 0.9.0, 0.9.1, 0.9.2, 0.9.3, 0.10.0, 0.10.1, 0.10.2, 0.11.0, 0.12.0, 0.13.0, 0.13.1, 0.14.0, 0.14.1, 0.14.2, 0.14.3, 0.14.4, 0.15.0, 0.15.1, 0.15.2, 0.15.3, 0.16.0, 0.16.1, 0.16.2, 0.16.3, 0.16.4, 0.16.5, 0.16.6, 0.17.0, 0.17.1, 0.17.2, 0.17.3, 0.17.4, 0.18.0, 0.18.1, 0.18.2, 0.18.3, 0.18.4, 0.19.0, 0.20.0, 0.20.1, 0.20.2, 0.21.0, 0.21.1, 0.21.2, 0.21.4, 0.21.5, 0.21.6, 0.22.0a0, 0.22.0b0, 0.22.0b1, 0.22.0b2, 0.22.0b3, 0.22.0b4, 0.22.0b5, 0.22.0b6, 0.22.0, 0.22.1, 0.22.2, 0.22.3, 0.22.4, 0.22.5, 1.0.0, 1.0.1, 1.0.2, 1.0.3, 1.0.5, 1.1.0, 1.1.1, 1.1.2, 1.1.3, 1.1.4, 1.1.5, 1.1.6, 1.2.0, 1.3.0, 1.3.1, 1.3.2, 1.3.3, 1.3.4, 1.3.5, 2.0.0rc1, 2.0.0, 2.0.1, 2.0.2, 2.0.3, 2.0.4, 2.0.5, 2.0.6, 2.0.6.post1, 2.0.7, 2.1.0, 2.2.0, 2.2.1, 2.2.2, 2.2.3, 2.2.4, 2.2.5, 2.3.0a1, 2.3.0a2, 2.3.0a4, 2.3.0, 2.3.1a1, 2.3.1, 2.3.2b2, 2.3.2b3, 2.3.2, 2.3.3, 2.3.4, 2.3.5, 2.3.6, 2.3.7, 2.3.8, 2.3.9, 2.3.10, 3.0.0b0)
ERROR: No matching distribution found for aiohttp>=3.0 (from yacron)

The following works:

virtualenv -p /usr/bin/python3 /yacron &&  /yacron/bin/pip install yacron==0.9.0

Rollbar Support

Description

I'd like the error reporting to support rollbar since we don't use Sentry. The email-based approach has been a bit unreliable for us (via gmail).

Thanks!

Support timezone schedule

Description

Can you support timezone setting for schedule task
ex:

jobs:
  - name: timezone LA
    command: echo "foobar"
    shell: /bin/bash
    schedule: "0 0 * * *"
    timezone: "America/Los_Angeles"

current yacron only support utc and localtime
but I need to run multiple timezone tasks in one yacron process

Can you support the feature?
Thanks

how can I stop yacron job?

  • Yet Another Cron version: latest version
  • Python version: 3.6
  • Operating System: linux centos6

yacron is a very modern and useful program!
In crontab, I can use the -l and -e options to check or stop a running job.
yacron doesn't seem to offer that option.
Do I have to kill a process to stop a running yacron job? Or is there a better way?
I need your help :)

wrong task start time(due to UTC)

yacron run inside docker alpine 3.6 based
python 3.6.1
timezone(America/Montreal) in the container and on the host is the same.

jobs:
- name: everydayat1
  command: python3 -u /xxx/xxxx/xxxx/xxxx.py
  schedule: "0 1 * * *"

but task start at 20:00 the previous day.

go to source https://github.com/gjcarneiro/yacron/blob/master/yacron/cron.py and see

def get_now() -> datetime.datetime:
return datetime.datetime.utcnow()

goto container with yacron, run python

# python3
Python 3.6.1 (default, Oct  2 2017, 20:46:59) 
[GCC 6.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
»> import datetime
»> datetime.datetime.utcnow()
datetime.datetime(2017, 12, 21, 10, 13, 3, 834821)
»> datetime.datetime.now()
datetime.datetime(2017, 12, 21, 5, 13, 28, 419075)

is it possible to add a setting to the Tasks
UTC = 1
UTC = 0
?

thank you for your time,
sincerely.

correct way for curl command

  • Yet Another Cron version: 0.17
  • Python version: 3.8
  • Operating System: bullseye

Description

Task marked fail but command success, im setting up to hourly download image for background override, the curl command is succes file downloaded correctly but yacron mark it as fail. Should i encapsulate with bash -c 'curl -L https://picsum.photos/3840/2160.jpg -o /var/www/html/public/img/bg1.jpg ?

heimdall_web.1.h28pgdlkajyr@homelab    | INFO:yacron:Starting job background-update
heimdall_web.1.h28pgdlkajyr@homelab    | INFO:yacron:Job background-update spawned
heimdall_web.1.h28pgdlkajyr@homelab    | [background-update stderr]   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
heimdall_web.1.h28pgdlkajyr@homelab    | [background-update stderr]                                  Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100  607k    0  607k    0     0   186k      0 --:--:--  0:00:03 --:--:--  344k
heimdall_web.1.h28pgdlkajyr@homelab    | INFO:yacron:Job background-update exit code 0; has stdout: false, has stderr: true; fail_reason: 'failsWhen=producesStderr and stderr is not empty'
heimdall_web.1.h28pgdlkajyr@homelab    | INFO:yacron:Job background-update STDERR:
heimdall_web.1.h28pgdlkajyr@homelab    |   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
heimdall_web.1.h28pgdlkajyr@homelab    |                                  Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100  607k    0  607k    0     0   186k      0 --:--:--  0:00:03 --:--:--  344k
heimdall_web.1.h28pgdlkajyr@homelab    | INFO:yacron:Cron job background-update: reporting failure
heimdall_web.1.h28pgdlkajyr@homelab    | INFO:yacron:Cron job background-update: reporting permanent failure

jobs definintion

jobs:
  - name: background-update
    command: curl -L https://picsum.photos/3840/2160.jpg -o /var/www/html/public/img/bg1.jpg
    shell: /bin/bash
    schedule: "0 * * * *"

Allow start without jobs

  • Yet Another Cron version: N/A
  • Python version: 3
  • Operating System: Ubuntu

Description

It would be great if jobs was non require parameter.
I use docker and have following structure of configurations:

/etc/yacron.d/
base.yml
dev.yml

base.yml - contains all default tasks. This file store in repository, and used in production.
dev.yml - local file, which is specific for each developer.
After project installation dev.yml is empty by default, but yacron breaks without jobs section.

What I Did

ERROR:yacron:Configuration error: when expecting a mapping
found a blank string
in "/etc/yacron.d/dev.yml", line 1, column 1:

Sentry: fingerprint option doesn't appear to be working

  • Yet Another Cron version: 0.13 (binary)
  • Python version: 3.8
  • Operating System: ubuntu

Based on production use, running in Kubernetes, a cron jobs that fails creates an Issue in Sentry. When the pod is replaced by a new pod, which changes its hostname, the failing cron job will then create a new Issue in Sentry. Even though I have this in the config:

  onFailure:
    report:
      sentry:
        dsn:
          fromEnvVar: SENTRY_DSN
        fingerprint:
          - yacron
          - "{{ name }}"

It's as if the fingerprint is being ignored and instead the default sentry_sdk fingerprint is being used instead...

Might have been broken by some sentry_sdk upgrade. Needs debugging.

Broken after 0.12.0 update

  • Yacron version: 0.12.0
  • Python version: 3.5.3
  • System: Debian Stretch

Description

After updating yacron to the latest 0.12.0 version it won't run anymore and outputs a error message.

What I Did

I executed

yaxron

Error message:

Traceback (most recent call last):
  File "/usr/local/bin/yacron", line 7, in <module>
    from yacron.__main__ import main
  File "/home/idev/.local/lib/python3.5/site-packages/yacron/__main__.py", line 8, in <module>
    from yacron.cron import Cron, ConfigError
  File "/home/idev/.local/lib/python3.5/site-packages/yacron/cron.py", line 10, in <module>
    from yacron.config import (
  File "/home/idev/.local/lib/python3.5/site-packages/yacron/config.py", line 363
    environ: Dict[str, str] = {}
           ^
SyntaxError: invalid syntax

Unexpected stacktrace with `@reboot`

  • Yet Another Cron version: 0.8.0
  • Python version: 3.7
  • Operating System: alpine 3.8

Description

Trying to run a simple echo upon startup (i.e. using @reboot)

What I Did

Running insider docker, using the example Dockerfile as a reference. Here's config file:

defaults:
  concurrencyPolicy: Forbid
jobs:
  - name: startup
    command: 'echo "Running!"'
    schedule: '@reboot'

and here's the output (as captured by docker logs)

INFO:yacron:Starting job startup
Running!
INFO:yacron:Job startup spawned
INFO:yacron:Job startup exit code 0; has stdout: false, has stderr: false; failed: false
INFO:yacron:Cron job startup: reporting success

so far so good... but soon it's followed by

Traceback (most recent call last):
  File "/usr/local/bin/yacron", line 11, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.7/site-packages/yacron/__main__.py", line 44, in main
    main_loop(_loop)
  File "/usr/local/lib/python3.7/site-packages/yacron/__main__.py", line 31, in main_loop
    loop.run_until_complete(cron.run())
  File "/usr/local/lib/python3.7/asyncio/base_events.py", line 568, in run_until_complete
    return future.result()
  File "/usr/local/lib/python3.7/site-packages/yacron/cron.py", line 73, in run
    await self.spawn_jobs(startup)
  File "/usr/local/lib/python3.7/site-packages/yacron/cron.py", line 107, in spawn_jobs
    if crontab.test(get_now(job.utc)):
AttributeError: 'str' object has no attribute 'test'
ERROR:asyncio:Task was destroyed but it is pending!
task: <Task pending coro=<Cron._wait_for_running_jobs() running at /usr/local/lib/python3.7/site-packages/yacron/cron.py:161> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x7f0e33ca73d8>()]>>
ERROR:asyncio:Task was destroyed but it is pending!
task: <Task pending coro=<Event.wait() running at /usr/local/lib/python3.7/asyncio/locks.py:293> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x7f0e305e8e88>()]> cb=[_release_waiter(<Future pendi...e33ca73d8>()]>)() at /usr/local/lib/python3.7/asyncio/tasks.py:362]>

Happy to provide any additional info!

Sharing defaults across other yml files

  • Yet Another Cron version: 0.11.2
  • Python version: 3..8
  • Operating System: Ubuntu

Description

Hi, and thanks for putting this tool together.

I have multiple yacron yml files that I keep separated for organizational purposes. I also have a single defaults.yml that has my web and defaults sections. I had hoped that the defaults would get picked up and used for all other schedules that get picked up in that directory, but it doesn't seem to be working in all cases.

All of the various schedule files get ingested (can see that with /status) and the web section is definitely being read as the web endpoint is up. But it seems like some of the defaults section are being ignored or overridden. These settings worked when I had everything in a single file. But one of my jobs got a "failure" because it saw stderr, with the following message that conflicts with my settings:

has stderr: true; fail_reason: 'failsWhen=producesStderr and stderr is not empty'

So I know it's picking up my defaults.yml because the web interface comes up, but it seems to be not picking up, or overriding some of the other sections. Is this expected?

Note: none of my other files have a defaults section or touch any of these settings.

Example defaults.yml

web:
  listen:
    - http://0.0.0.0:8030

defaults:
  shell: /bin/bash
  utc: false
  timezone: America/New_York
  concurrencyPolicy: Forbid
  executionTimeout: 600
  killTimeout: 10
  captureStderr: true
  captureStdout: true
  failsWhen:
    producesStdout: false
    producesStderr: false
    nonzeroReturn: true
    always: false
  onFailure:
    report:
      mail:
        from: <from email>
        to: <to email>
        smtpHost: smtp.gmail.com
        username: <username>
        password:
          fromEnvVar: <password env var>
        tls: true
        starttls: true
    retry:
      maximumRetries: 1
      initialDelay: 30
      maximumDelay: 60
      backoffMultiplier: 1

Feature request: logging reporter

Hi,

I would like to write the successful executions to a file, but I think it would be better to support logging to configure logs. In the Python documentation there is an example in Yaml:

https://docs.python.org/3/howto/logging.html#configuring-logging
https://docs.python.org/3/library/logging.config.html#dictionary-schema-details

It is only necessary to configure a handler and a format. Loggers can be dynamically created from jobs.

My proposal:

- name: test-01
  command: |
    echo "hello" 1>&2
    sleep 1
    exit 10
  schedule:
    minute: "*/2"
  captureStderr: true
  onFailure:
    report:
      logging:
      	format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
      	handler:
      	  class: logging.StreamHandler
          stream: ext://sys.stdout

Supporting the logging module allows to use many other handlers such as rsyslog.

Feature Request: activate / deactivate Jobs

  • Yet Another Cron version: yacron-0.17.0-x86_64-unknown-linux-gnu
  • Python version: -
  • Operating System: Docker/Ubuntu

Description

we use Yacron in Docker environments. A couple of the Job-configuration entries is generated or partly replaced through String-Operations at container startup. E.g. our yaml contains
- name: job_myJob
command:
- /opt/myScript.sh
schedule: "REPLACEME_AT_STARTUP"

The schedule in turn is configured through environment variables in a Kubernets cluster. We deliver just "Yacron-Yaml-Templates" to the container (following the above pattern).

The feature request: to make above overall-setups more easy it would be convient to have a new switch "active:[true|false]", Default=true for the Job-configuration. It is then possible to privide Default Job-Yamls and let activate single Jobs at container-startup-time through configuration.

email: Missing required header field: "Date"

  • Yet Another Cron version: 0.11.2
  • Python version: 3.8.7
  • Operating System: Alpine Linux 3.13.1

Description

The spam filter amavisd flags emails send by yacron with:
X-Amavis-Alert: BAD HEADER SECTION, Missing required header field: "Date"

`
INVALID HEADER: MISSING REQUIRED HEADER FIELD
Missing required header field: "Date"

The RFC 5322 document specifies rules for forming internet messages.
Section '3.6. Field Definitions' specifies that certain header fields
are required (origination date field and the "From:" originator field).
`

What I Did

yacron with configured email reporting.

Cannot run the binary in alpine linux

  • Yet Another Cron version: 0.16.0
  • Operating System: Linux 8b410fb6a95c 5.10.16.3 # 1 SMP Fri Apr 2 22:23:49 UTC 2021 x86_64 Linux

Hello, forts of all, thanks for a great tool, it is one of the best tools I have ever used!

I am trying to use yacron in alpine Linux inside docker container.
To keep the container as small as possible, I am using the compiled binary, but unfortunately it does not work in alpine.
Is there any possible way how to make it work without installing Python to the system?

ldd utility shows this

 ldd yacron
        /lib64/ld-linux-x86-64.so.2 (0x7ffa9788d000)
        libdl.so.2 => /lib64/ld-linux-x86-64.so.2 (0x7ffa9788d000)
        libz.so.1 => /lib/libz.so.1 (0x7ffa97873000)
        libpthread.so.0 => /lib64/ld-linux-x86-64.so.2 (0x7ffa9788d000)
        libc.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7ffa9788d000)
Error relocating yacron: __strcat_chk: symbol not found
Error relocating yacron: __snprintf_chk: symbol not found
Error relocating yacron: __vfprintf_chk: symbol not found
Error relocating yacron: __realpath_chk: symbol not found
Error relocating yacron: __strdup: symbol not found
Error relocating yacron: __memcpy_chk: symbol not found
Error relocating yacron: __vsnprintf_chk: symbol not found
Error relocating yacron: __strcpy_chk: symbol not found
Error relocating yacron: __fread_chk: symbol not found
Error relocating yacron: __fprintf_chk: symbol not found

Sentry: change sentry_sdk.utils.MAX_STRING_LENGTH

The default limit is 512, and it gets applied to the body of the message. It is way too low a limit for most errors. For example, in Python scripts, I can only see the very top of the Traceback, it is useless.

Need to change it to a more sensible default (16k?), as well as have a config option allowing to change it.

Bug in interaction between job retries state and concurrencyPolicy

If a job has failed and is waiting the backoff to retry, then we enter a new minute and another instance of the job tries to fire off, things can go wrong, depending on the concurrencyPolicy. We need to cancel the retry before attempting to launch a new regularly scheduled instance of the job.

Package binaries for all releases?

Hi,

Thanks for this tool!

Release 0.10.0 featured a binary, which was really helpful in installing yacron without having to deal with a base image's installed python version.

Could newer releases also be packaged that way and published?

For reference, this is how we pull yacron:

ARG YACRON_BASE_URL=https://github.com/gjcarneiro/yacron/releases/download
ARG YACRON_VERSION=0.10.0
RUN curl -sSL -o yacron.xz $YACRON_BASE_URL/$YACRON_VERSION/yacron-$YACRON_VERSION-x86_64-unknown-linux-gnu.xz && \
  unxz yacron.xz && \
  chmod +x yacron

asyncio.exceptions.LimitOverrunError

  • Yet Another Cron version: 0.14.0
  • Python version: 3.9
  • Operating System: python 3.9-slim-buster docker image.

Description

When sending multiple requests.get API calls , suddenly one call errors out ( same call everytime ) with the following message.

[touchstone stderr] < Host: abc.com:8080
[touchstone stderr] < User-Agent: python-requests/2.26.0
[touchstone stderr] < Accept-Encoding: gzip, deflate
[touchstone stderr] < Accept: */*
[touchstone stderr] < Connection: keep-alive
[touchstone stderr] < 
[touchstone stderr] 
[touchstone stderr] > HTTP/1.1 200 OK
[touchstone stderr] > Content-Type: application/json
[touchstone stderr] > content-encoding: gzip
[touchstone stderr] > transfer-encoding: chunked
[touchstone stderr] > 
ERROR:yacron:please report this as a bug (2)
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/asyncio/streams.py", line 540, in readline
    line = await self.readuntil(sep)
  File "/usr/local/lib/python3.9/asyncio/streams.py", line 635, in readuntil
    raise exceptions.LimitOverrunError(
asyncio.exceptions.LimitOverrunError: Separator is found, but chunk is longer than limit

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/yacron/cron.py", line 356, in _wait_for_running_jobs
    task.result()
  File "/usr/local/lib/python3.9/site-packages/yacron/job.py", line 420, in wait
    await self._read_job_streams()
  File "/usr/local/lib/python3.9/site-packages/yacron/job.py", line 427, in _read_job_streams
    ) = await self._stderr_reader.join()
  File "/usr/local/lib/python3.9/site-packages/yacron/job.py", line 76, in join
    await self._reader
  File "/usr/local/lib/python3.9/site-packages/yacron/job.py", line 54, in _read
    line = (await stream.readline()).decode("utf-8")
  File "/usr/local/lib/python3.9/asyncio/streams.py", line 549, in readline
    raise ValueError(e.args[0])
ValueError: Separator is found, but chunk is longer than limit```

Describe what you were trying to get done.
Tell us what happened, what went wrong, and what you expected to happen.
When I run it from outside without "yacron" it works just fine. 

### What I Did

Paste the command(s) you ran and the output.
If there was a crash, please include the traceback here.

Error when starting yacron

  • Yet Another Cron version: 0.12.0
  • Python version: 3.8
  • Operating System: Alpine

Description

I want to replace crond by yacron in an Alpine based docker. Unfortunately I have an error when I try to use yacron.

It was previously working but right now it is not working anymore. I suspect latest ruamel update to break something. What do you think ?

What I Did

Commands to install yacron

python3 -m venv yacronenv && \
. yacronenv/bin/activate && \
pip install yacron

Command used to run yacron

/yacronenv/bin/yacron -c /home/foo/crontab.yml

Configuration file /home/foo/crontab.yml

jobs:
  - name: speedtest
    command: /opt/speedtest2mqtt.sh
    shell: /bin/bash
    schedule: "*/5 * * * *"
    env_file: /var/tmp/container.env
    captureStderr: false
    captureStdout: true
    concurrencyPolicy: Forbid

Traceback (most recent call last):
  File "/yacronenv/bin/yacron", line 8, in <module>
    sys.exit(main())
  File "/yacronenv/lib/python3.8/site-packages/yacron/__main__.py", line 56, in main
    main_loop(_loop)
  File "/yacronenv/lib/python3.8/site-packages/yacron/__main__.py", line 31, in main_loop
    cron = Cron(args.config)
  File "/yacronenv/lib/python3.8/site-packages/yacron/cron.py", line 86, in __init__
    self.update_config()
  File "/yacronenv/lib/python3.8/site-packages/yacron/cron.py", line 145, in update_config
    config, web_config = parse_config(self.config_arg)
  File "/yacronenv/lib/python3.8/site-packages/yacron/config.py", line 434, in parse_config
    config, web_config = parse_config_file(config_arg)
  File "/yacronenv/lib/python3.8/site-packages/yacron/config.py", line 347, in parse_config_file
    return parse_config_string(data, path)
  File "/yacronenv/lib/python3.8/site-packages/yacron/config.py", line 388, in parse_config_string
    doc = strictyaml.load(data, CONFIG_SCHEMA, label=path).data
  File "/yacronenv/lib/python3.8/site-packages/strictyaml/parser.py", line 318, in load
    return generic_load(yaml_string, schema=schema, label=label)
  File "/yacronenv/lib/python3.8/site-packages/strictyaml/parser.py", line 280, in generic_load
    document = ruamelyaml.load(yaml_string, Loader=DynamicStrictYAMLLoader)
  File "/yacronenv/lib/python3.8/site-packages/ruamel/yaml/main.py", line 1067, in load
    return loader._constructor.get_single_data()
  File "/yacronenv/lib/python3.8/site-packages/ruamel/yaml/constructor.py", line 122, in get_single_data
    return self.construct_document(node)
  File "/yacronenv/lib/python3.8/site-packages/ruamel/yaml/constructor.py", line 132, in construct_document
    for _dummy in generator:
  File "/yacronenv/lib/python3.8/site-packages/ruamel/yaml/constructor.py", line 1619, in construct_yaml_map
    self.construct_mapping(node, data, deep=True)
  File "/yacronenv/lib/python3.8/site-packages/strictyaml/parser.py", line 83, in construct_mapping
    value = self.construct_object(value_node, deep=deep)
  File "/yacronenv/lib/python3.8/site-packages/ruamel/yaml/constructor.py", line 155, in construct_object
    data = self.construct_non_recursive_object(node)
  File "/yacronenv/lib/python3.8/site-packages/ruamel/yaml/constructor.py", line 197, in construct_non_recursive_object
    for _dummy in generator:
  File "/yacronenv/lib/python3.8/site-packages/ruamel/yaml/constructor.py", line 1611, in construct_yaml_seq
    data.extend(self.construct_rt_sequence(node, data))
  File "/yacronenv/lib/python3.8/site-packages/ruamel/yaml/constructor.py", line 1322, in construct_rt_sequence
    if self.loader and self.loader.comment_handling is None:
AttributeError: 'DynamicStrictYAMLLoader' object has no attribute 'comment_handling'

Job is always executed immediately on yacron start

  • Yet Another Cron version: 0.16.0
  • Python version: embedded
  • Operating System: ubuntu20

Description

The following job gets executed as soon as I start the yacron binary:

jobs:
  - name: test-01
    command: echo "foobar"
    shell: /bin/bash
    schedule: "* * * * *"

But it should only be triggered every whole minute.

AttributeError: 'str' object has no attribute 'matchers'

  • Yet Another Cron version: yacron-0.10.0-py3-none-any.whl
  • Python version: 3.7
  • Operating System: Docker ubuntu:bionic & ubuntu:eoan (same result on both)

Description

I'm trying to run this jobfile in /etc/yacron.d/jobs.yaml:

web:
  listen:
    - http://127.0.0.1:8000
    - unix:///tmp/yacron.sock

defaults:
  shell: /bin/bash
  utc: false
  captureStdout: true
  captureStderr: true
  onFailure:
    report:
      mail:
        from: [email protected]
        to: [email protected]
        smtpHost: mail.example.com
    retry:
      maximumRetries: 3
      initialDelay: 600
      maximumDelay: 9600
      backoffMultiplier: 2

jobs:
  - name: rsnapshot-hourly
    command: /usr/bin/rsnapshot hourly
    schedule: "0 */6 * * *"
    # every 6 hours

  - name: rsnapshot-daily
    command: /usr/bin/rsnapshot daily
    schedule: "0 2 * * *"
    # 2am every day

  - name: rsnapshot-weekly
    command: /usr/bin/rsnapshot weekly
    schedule: "0 5 * * 0"
    # 5am sunday every week

  - name: rsnapshot-monthly
    command: /usr/bin/rsnapshot monthly
    schedule: "0 6 1 * *"
    # 6am on the first of every month

  - name: zsnapshot-Monadical
    command: ssh pumpkin '/usr/sbin/zfs snapshot "ssd-pumpkin/Monadical@"'$(date +"%Y-%m-%d_%H-%M")
    schedule: "0 0 */3 * *"

  - name: zsnapshot-opt
    command: ssh pumpkin '/usr/sbin/zfs snapshot "ssd-pumpkin/opt@"'$(date +"%Y-%m-%d_%H-%M")'
    schedule: "0 0 */3 * *"

stout & stderr

Output from /yacron/bin/yacron:

yacron_1  | INFO:yacron:web: started listening on http://127.0.0.1:8000
yacron_1  | INFO:yacron:web: started listening on unix:///tmp/yacron.sock
yacron_1  | Traceback (most recent call last):
yacron_1  |   File "/yacron/bin/yacron", line 8, in <module>
yacron_1  |     sys.exit(main())
yacron_1  |   File "/yacron/lib/python3.7/site-packages/yacron/__main__.py", line 56, in main
yacron_1  |     main_loop(_loop)
yacron_1  |   File "/yacron/lib/python3.7/site-packages/yacron/__main__.py", line 43, in main_loop
yacron_1  |     loop.run_until_complete(cron.run())
yacron_1  |   File "/usr/lib/python3.7/asyncio/base_events.py", line 579, in run_until_complete
yacron_1  |     return future.result()
yacron_1  |   File "/yacron/lib/python3.7/site-packages/yacron/cron.py", line 123, in run
yacron_1  |     await self.spawn_jobs(startup)
yacron_1  |   File "/yacron/lib/python3.7/site-packages/yacron/cron.py", line 247, in spawn_jobs
yacron_1  |     if startup and job.schedule == "@reboot":
yacron_1  |   File "/yacron/lib/python3.7/site-packages/crontab/_crontab.py", line 389, in __eq__
yacron_1  |     match_last = self.matchers[1:] == other.matchers[1:]
yacron_1  | AttributeError: 'str' object has no attribute 'matchers'
yacron_1  | ERROR:asyncio:Task was destroyed but it is pending!
yacron_1  | task: <Task pending coro=<Cron._wait_for_running_jobs() running at /yacron/lib/python3.7/site-packages/yacron/cron.py:321> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x7f7e0a3b38d0>()]>>
yacron_1  | ERROR:asyncio:Task was destroyed but it is pending!
yacron_1  | task: <Task pending coro=<Event.wait() running at /usr/lib/python3.7/asyncio/locks.py:293> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x7f7e0a3fb0d0>()]> cb=[_release_waiter(<Future pendi...e0a3b38d0>()]>)() at /usr/lib/python3.7/asyncio/tasks.py:392]>

Propose: permanent tasks

  • Yet Another Cron version: 0.18.0
  • Python version: 3.9.2
  • Operating System: Linux

Description

I run a permanent (infinity-running) task with concurrencyPolicy: Forbid.
This produce a warning:

WARNING:yacron:Job task-name: still running and concurrencyPolicy is Forbid

Propose

It would be great to add concurrencyPolicy: Permanent (or something else) to suppress the warning.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.